initial key provisioning demo working

This commit is contained in:
bunnie 2021-08-07 22:21:49 +08:00
parent 86845dd093
commit bc6ec8caf4
13 changed files with 1291 additions and 820 deletions

256
precursors/rom.db Normal file → Executable file
View file

@ -1,128 +1,128 @@
KEYROM 0 A SLICE_X36Y50 b'c3a0e2b132d2f31e'
KEYROM 0 B SLICE_X36Y50 b'2ca56f199524c45d'
KEYROM 0 C SLICE_X36Y50 b'eda510da53bf8cc4'
KEYROM 0 D SLICE_X36Y50 b'c188087aa2ec96d0'
KEYROM 1 A SLICE_X37Y50 b'7ee6ea370ad2fe5c'
KEYROM 1 B SLICE_X37Y50 b'4aa8f7fcdd02326f'
KEYROM 1 C SLICE_X37Y50 b'd847ed542da2a44f'
KEYROM 1 D SLICE_X37Y50 b'851060cd1389a654'
KEYROM 2 A SLICE_X36Y51 b'0465fe16934897a2'
KEYROM 2 B SLICE_X36Y51 b'26ce3719ef29809b'
KEYROM 2 C SLICE_X36Y51 b'70b7fa0f33ee7f0c'
KEYROM 2 D SLICE_X36Y51 b'b47f2cbdc35c9247'
KEYROM 3 A SLICE_X37Y51 b'9a4d29fe5eec4757'
KEYROM 3 B SLICE_X37Y51 b'7df4a143ae4a7caa'
KEYROM 3 C SLICE_X37Y51 b'1af63092ba3fefa2'
KEYROM 3 D SLICE_X37Y51 b'3f1c14d0ba5ba72e'
KEYROM 4 A SLICE_X36Y52 b'40c14b1e5630c3a4'
KEYROM 4 B SLICE_X36Y52 b'b871f9de6c4b74c0'
KEYROM 4 C SLICE_X36Y52 b'84e1def501c588fb'
KEYROM 4 D SLICE_X36Y52 b'e7553ded600994ac'
KEYROM 5 A SLICE_X37Y52 b'd20804a0ed7efe1c'
KEYROM 5 B SLICE_X37Y52 b'ba36a98a7010e5e5'
KEYROM 5 C SLICE_X37Y52 b'd5907c3f23a1442d'
KEYROM 5 D SLICE_X37Y52 b'd65c5d2d7c5a3798'
KEYROM 6 A SLICE_X36Y53 b'2d8c6317e1f6b8a1'
KEYROM 6 B SLICE_X36Y53 b'de9ed0b5156ee3d3'
KEYROM 6 C SLICE_X36Y53 b'11f355c942161ec7'
KEYROM 6 D SLICE_X36Y53 b'fbd0d6b72ef33027'
KEYROM 7 A SLICE_X37Y53 b'914b578244116537'
KEYROM 7 B SLICE_X37Y53 b'7f6db6dd8ef69b39'
KEYROM 7 C SLICE_X37Y53 b'32e3e4f56a617aa2'
KEYROM 7 D SLICE_X37Y53 b'8ea9b280f9a9e78a'
KEYROM 8 A SLICE_X36Y54 b'be03b1a096290f64'
KEYROM 8 B SLICE_X36Y54 b'ffa98648a3196b8d'
KEYROM 8 C SLICE_X36Y54 b'88bac8cd859e7963'
KEYROM 8 D SLICE_X36Y54 b'be0cf1198b720088'
KEYROM 9 A SLICE_X37Y54 b'150b03fdc35cffb8'
KEYROM 9 B SLICE_X37Y54 b'10efffba5c00dc08'
KEYROM 9 C SLICE_X37Y54 b'199523c7ad081e0e'
KEYROM 9 D SLICE_X37Y54 b'3dc86a72c75ad38a'
KEYROM 10 A SLICE_X36Y55 b'3ab20094c1bc3788'
KEYROM 10 B SLICE_X36Y55 b'672ce21657d15645'
KEYROM 10 C SLICE_X36Y55 b'999635ee37381c37'
KEYROM 10 D SLICE_X36Y55 b'd85f5b0df1be66fa'
KEYROM 11 A SLICE_X37Y55 b'01fc41acd00c0376'
KEYROM 11 B SLICE_X37Y55 b'c83f7effdd5e2865'
KEYROM 11 C SLICE_X37Y55 b'4bb31612900f38aa'
KEYROM 11 D SLICE_X37Y55 b'3346dd9800df334f'
KEYROM 12 A SLICE_X36Y56 b'5547b1eae3398d4f'
KEYROM 12 B SLICE_X36Y56 b'c2a761373bdfeadc'
KEYROM 12 C SLICE_X36Y56 b'1c9c0e67e0d6dd6d'
KEYROM 12 D SLICE_X36Y56 b'75eea4f26017e9d7'
KEYROM 13 A SLICE_X37Y56 b'3e57f26d8bd60162'
KEYROM 13 B SLICE_X37Y56 b'dec91b14c25e2f66'
KEYROM 13 C SLICE_X37Y56 b'73b87b32387b7298'
KEYROM 13 D SLICE_X37Y56 b'2d5b8b7306a65caa'
KEYROM 14 A SLICE_X36Y57 b'4e09d069d040baf6'
KEYROM 14 B SLICE_X36Y57 b'a9d2df3f8954f7a8'
KEYROM 14 C SLICE_X36Y57 b'0b696c38ed59c638'
KEYROM 14 D SLICE_X36Y57 b'55871008fee18aa2'
KEYROM 15 A SLICE_X37Y57 b'e79e503241d13516'
KEYROM 15 B SLICE_X37Y57 b'92a6565b4a7664c0'
KEYROM 15 C SLICE_X37Y57 b'069895a86f2c79e9'
KEYROM 15 D SLICE_X37Y57 b'0edfc25b603d6cce'
KEYROM 16 A SLICE_X36Y58 b'1b1a656e9cfa599b'
KEYROM 16 B SLICE_X36Y58 b'5bec33557444d5ba'
KEYROM 16 C SLICE_X36Y58 b'008f6b2f81c29561'
KEYROM 16 D SLICE_X36Y58 b'5c04e9520239826e'
KEYROM 17 A SLICE_X37Y58 b'd66fe6aaa356493a'
KEYROM 17 B SLICE_X37Y58 b'05eff990ab0dbca8'
KEYROM 17 C SLICE_X37Y58 b'01757c16edf587e2'
KEYROM 17 D SLICE_X37Y58 b'1b4f6b04aabaaba6'
KEYROM 18 A SLICE_X36Y59 b'85db56743658bd5c'
KEYROM 18 B SLICE_X36Y59 b'd0805089c70677e6'
KEYROM 18 C SLICE_X36Y59 b'b5791a9510679b1f'
KEYROM 18 D SLICE_X36Y59 b'7007f1bc3e5842d0'
KEYROM 19 A SLICE_X37Y59 b'bf16ac68faa50b01'
KEYROM 19 B SLICE_X37Y59 b'efeaab7b47b6403f'
KEYROM 19 C SLICE_X37Y59 b'8dd5405a4eab5a08'
KEYROM 19 D SLICE_X37Y59 b'd25414a37496bd3d'
KEYROM 20 A SLICE_X36Y60 b'bf3ee8312bd0870b'
KEYROM 20 B SLICE_X36Y60 b'7491ab56dafbef9c'
KEYROM 20 C SLICE_X36Y60 b'20356eda0267c983'
KEYROM 20 D SLICE_X36Y60 b'a9d60b973dd19a85'
KEYROM 21 A SLICE_X37Y60 b'ebcde3cbcbea9168'
KEYROM 21 B SLICE_X37Y60 b'718daec18f71e60f'
KEYROM 21 C SLICE_X37Y60 b'3225102d796a019a'
KEYROM 21 D SLICE_X37Y60 b'b97ee41b5d611eb2'
KEYROM 22 A SLICE_X36Y61 b'90483617e30e112d'
KEYROM 22 B SLICE_X36Y61 b'ebd4e144c76ad69e'
KEYROM 22 C SLICE_X36Y61 b'836adbc2d2b9135b'
KEYROM 22 D SLICE_X36Y61 b'8a6f50d59c5222f3'
KEYROM 23 A SLICE_X37Y61 b'6fcb8d91c93b88e7'
KEYROM 23 B SLICE_X37Y61 b'33fd35b6775ee619'
KEYROM 23 C SLICE_X37Y61 b'ded05bf353967b43'
KEYROM 23 D SLICE_X37Y61 b'0847bab859ee97c3'
KEYROM 24 A SLICE_X36Y62 b'3e7f120884e00484'
KEYROM 24 B SLICE_X36Y62 b'a0d25326292916af'
KEYROM 24 C SLICE_X36Y62 b'f00d5be2a1dd5028'
KEYROM 24 D SLICE_X36Y62 b'040270fb966aeadb'
KEYROM 25 A SLICE_X37Y62 b'982ade51ade336fe'
KEYROM 25 B SLICE_X37Y62 b'1aec6c88e99d8be2'
KEYROM 25 C SLICE_X37Y62 b'f8ac7f661d70d002'
KEYROM 25 D SLICE_X37Y62 b'9d5f71254a856e8e'
KEYROM 26 A SLICE_X36Y63 b'c603bbcbdb8a1b4d'
KEYROM 26 B SLICE_X36Y63 b'3b4ead9cf990e112'
KEYROM 26 C SLICE_X36Y63 b'd825e8f3a34d29d4'
KEYROM 26 D SLICE_X36Y63 b'6dbccc3bca6b3534'
KEYROM 27 A SLICE_X37Y63 b'12ba32f22165572d'
KEYROM 27 B SLICE_X37Y63 b'98f94f235907579d'
KEYROM 27 C SLICE_X37Y63 b'd184af07800e0ecc'
KEYROM 27 D SLICE_X37Y63 b'655e262876efc1c3'
KEYROM 28 A SLICE_X36Y64 b'849ead535c1b4fce'
KEYROM 28 B SLICE_X36Y64 b'f59721f21bbaf649'
KEYROM 28 C SLICE_X36Y64 b'cc4c9a7717eb4dd4'
KEYROM 28 D SLICE_X36Y64 b'618ed39fbed2924a'
KEYROM 29 A SLICE_X37Y64 b'36513623ac1716a6'
KEYROM 29 B SLICE_X37Y64 b'038b21fdaffdcda1'
KEYROM 29 C SLICE_X37Y64 b'585ef63e34650453'
KEYROM 29 D SLICE_X37Y64 b'eaece498c0c8ee5d'
KEYROM 30 A SLICE_X36Y65 b'3ce75a293ae01957'
KEYROM 30 B SLICE_X36Y65 b'bc940fd0f2ce9360'
KEYROM 30 C SLICE_X36Y65 b'14b887863092fd13'
KEYROM 30 D SLICE_X36Y65 b'a8964b349a1b7c17'
KEYROM 31 A SLICE_X37Y65 b'f3b82c2e1c20553c'
KEYROM 31 B SLICE_X37Y65 b'9f2aabc29ba378f8'
KEYROM 31 C SLICE_X37Y65 b'0f98135a942e951b'
KEYROM 31 D SLICE_X37Y65 b'b7ef321d5b96792a'
KEYROM 0 A SLICE_X36Y50 b'ed9040309fce38f4'
KEYROM 0 B SLICE_X36Y50 b'34b83a94e4408416'
KEYROM 0 C SLICE_X36Y50 b'8f088d95d0241a29'
KEYROM 0 D SLICE_X36Y50 b'71976c7c19e9b004'
KEYROM 1 A SLICE_X37Y50 b'23147e30bff2ec9a'
KEYROM 1 B SLICE_X37Y50 b'1fd3c7d928865270'
KEYROM 1 C SLICE_X37Y50 b'69affdc0d64bce09'
KEYROM 1 D SLICE_X37Y50 b'7a5d619fdd90768c'
KEYROM 2 A SLICE_X36Y51 b'e6a75fea68b97646'
KEYROM 2 B SLICE_X36Y51 b'3bbe4fd7491feae7'
KEYROM 2 C SLICE_X36Y51 b'8f1ce05eb6df82cf'
KEYROM 2 D SLICE_X36Y51 b'27262a3adbb299bb'
KEYROM 3 A SLICE_X37Y51 b'f51fe08930b42539'
KEYROM 3 B SLICE_X37Y51 b'fe0f77932c0955be'
KEYROM 3 C SLICE_X37Y51 b'75b2d1f824733c6e'
KEYROM 3 D SLICE_X37Y51 b'd7d7ba4db2a43551'
KEYROM 4 A SLICE_X36Y52 b'01adb0f69b2445b6'
KEYROM 4 B SLICE_X36Y52 b'f9615dc2835077a9'
KEYROM 4 C SLICE_X36Y52 b'48b9726cdadf5f5c'
KEYROM 4 D SLICE_X36Y52 b'b04e43398e8a5a48'
KEYROM 5 A SLICE_X37Y52 b'ff7bd4295aabdd2d'
KEYROM 5 B SLICE_X37Y52 b'71ed1b78bf6abef1'
KEYROM 5 C SLICE_X37Y52 b'711b0d7da395db20'
KEYROM 5 D SLICE_X37Y52 b'bab4a809cb8d5749'
KEYROM 6 A SLICE_X36Y53 b'4d30fac41aa32b0f'
KEYROM 6 B SLICE_X36Y53 b'43b00f6dcac70852'
KEYROM 6 C SLICE_X36Y53 b'ad4003d496e1977f'
KEYROM 6 D SLICE_X36Y53 b'4ae9ec045604171d'
KEYROM 7 A SLICE_X37Y53 b'926d630da7b7a38f'
KEYROM 7 B SLICE_X37Y53 b'ea9dcfbcee0e3e27'
KEYROM 7 C SLICE_X37Y53 b'331310550f7be1a3'
KEYROM 7 D SLICE_X37Y53 b'86654bf903647983'
KEYROM 8 A SLICE_X36Y54 b'5faf7f97fd1adda9'
KEYROM 8 B SLICE_X36Y54 b'bd9e98995dfeb80e'
KEYROM 8 C SLICE_X36Y54 b'ccc154e624fa6d30'
KEYROM 8 D SLICE_X36Y54 b'6d4cf1460bbcc9d7'
KEYROM 9 A SLICE_X37Y54 b'61a5187dac4451d5'
KEYROM 9 B SLICE_X37Y54 b'b0ad0aeed2998bc1'
KEYROM 9 C SLICE_X37Y54 b'f21d761d350fc65c'
KEYROM 9 D SLICE_X37Y54 b'b12550f563825b1e'
KEYROM 10 A SLICE_X36Y55 b'fd44ec8a47c67607'
KEYROM 10 B SLICE_X36Y55 b'6f73609c3f474a99'
KEYROM 10 C SLICE_X36Y55 b'97f3f40b00eff415'
KEYROM 10 D SLICE_X36Y55 b'd9a8030e01d2e969'
KEYROM 11 A SLICE_X37Y55 b'b69db3f2c7383567'
KEYROM 11 B SLICE_X37Y55 b'c84e2d58eed1667f'
KEYROM 11 C SLICE_X37Y55 b'8de4bf137da8b4a5'
KEYROM 11 D SLICE_X37Y55 b'4b44f068e3b6e954'
KEYROM 12 A SLICE_X36Y56 b'9f9dfa17fd8f813b'
KEYROM 12 B SLICE_X36Y56 b'd7e2dc46e49beed5'
KEYROM 12 C SLICE_X36Y56 b'3c147b86326a0df7'
KEYROM 12 D SLICE_X36Y56 b'6de9236fe18c43bb'
KEYROM 13 A SLICE_X37Y56 b'f96f763f484a7293'
KEYROM 13 B SLICE_X37Y56 b'ea9d3dc73170641a'
KEYROM 13 C SLICE_X37Y56 b'2045bb3e568b0ef8'
KEYROM 13 D SLICE_X37Y56 b'2ce220df70dfe05d'
KEYROM 14 A SLICE_X36Y57 b'0fd2db99d978d460'
KEYROM 14 B SLICE_X36Y57 b'83ce09c09327ae22'
KEYROM 14 C SLICE_X36Y57 b'195e32c556a026fd'
KEYROM 14 D SLICE_X36Y57 b'23627d617f5baf71'
KEYROM 15 A SLICE_X37Y57 b'c7f24e5f55a9cca9'
KEYROM 15 B SLICE_X37Y57 b'7820cea9a62feef3'
KEYROM 15 C SLICE_X37Y57 b'baf6949fc5db190d'
KEYROM 15 D SLICE_X37Y57 b'c208af523a7d55ef'
KEYROM 16 A SLICE_X36Y58 b'b1445a38b8cec3ec'
KEYROM 16 B SLICE_X36Y58 b'2e694e04676b83c6'
KEYROM 16 C SLICE_X36Y58 b'33b1fbd89e0b2d53'
KEYROM 16 D SLICE_X36Y58 b'74d20b1bc8765902'
KEYROM 17 A SLICE_X37Y58 b'65bdef7af5c88f77'
KEYROM 17 B SLICE_X37Y58 b'182f425b728098e6'
KEYROM 17 C SLICE_X37Y58 b'26a6e4b72e49a038'
KEYROM 17 D SLICE_X37Y58 b'476e499924be15c0'
KEYROM 18 A SLICE_X36Y59 b'b78c1c5cc2aa57a1'
KEYROM 18 B SLICE_X36Y59 b'31384d4342a6fda5'
KEYROM 18 C SLICE_X36Y59 b'05ae9c252ac885ce'
KEYROM 18 D SLICE_X36Y59 b'c96968631e3f7f78'
KEYROM 19 A SLICE_X37Y59 b'634d2885ce6e5855'
KEYROM 19 B SLICE_X37Y59 b'a3cf9e2e72e6e792'
KEYROM 19 C SLICE_X37Y59 b'581ffd047adcc9ea'
KEYROM 19 D SLICE_X37Y59 b'2f64b2ce422d5531'
KEYROM 20 A SLICE_X36Y60 b'7e329f3ca0aaa48e'
KEYROM 20 B SLICE_X36Y60 b'aea96c4e160d7c23'
KEYROM 20 C SLICE_X36Y60 b'6ae6580d67e7ff89'
KEYROM 20 D SLICE_X36Y60 b'5474386b42cab7f1'
KEYROM 21 A SLICE_X37Y60 b'3f9bd1bd08d4aff4'
KEYROM 21 B SLICE_X37Y60 b'e56106594063c796'
KEYROM 21 C SLICE_X37Y60 b'2195de30ceb285a2'
KEYROM 21 D SLICE_X37Y60 b'6334c328f262238f'
KEYROM 22 A SLICE_X36Y61 b'c7864968fa48d4fb'
KEYROM 22 B SLICE_X36Y61 b'539340a6115a09de'
KEYROM 22 C SLICE_X36Y61 b'5a481886017ce135'
KEYROM 22 D SLICE_X36Y61 b'53ab6dd8014367e1'
KEYROM 23 A SLICE_X37Y61 b'a96ce894e8ef46bc'
KEYROM 23 B SLICE_X37Y61 b'1bb558f3736ff921'
KEYROM 23 C SLICE_X37Y61 b'5f317c906fda756e'
KEYROM 23 D SLICE_X37Y61 b'a09db3281b82fcf1'
KEYROM 24 A SLICE_X36Y62 b'916fb25b3c623029'
KEYROM 24 B SLICE_X36Y62 b'3c36f54ab0b983c3'
KEYROM 24 C SLICE_X36Y62 b'564c5c49176dccd2'
KEYROM 24 D SLICE_X36Y62 b'6b2a7d1cb3402096'
KEYROM 25 A SLICE_X37Y62 b'dfd1cc0ccc9d6375'
KEYROM 25 B SLICE_X37Y62 b'773dc64635af690c'
KEYROM 25 C SLICE_X37Y62 b'87958a06b32192f6'
KEYROM 25 D SLICE_X37Y62 b'a9f627a1e12ff5fb'
KEYROM 26 A SLICE_X36Y63 b'e848ef1676025ddb'
KEYROM 26 B SLICE_X36Y63 b'631c42f2972d8f4e'
KEYROM 26 C SLICE_X36Y63 b'e1ba5f1db6c1213e'
KEYROM 26 D SLICE_X36Y63 b'd0a6beb90ebfa1ad'
KEYROM 27 A SLICE_X37Y63 b'aa6f2108de94b9d7'
KEYROM 27 B SLICE_X37Y63 b'94fdad0d7e5e032a'
KEYROM 27 C SLICE_X37Y63 b'cb3a7ed9fa0c188c'
KEYROM 27 D SLICE_X37Y63 b'd9115aa51962339f'
KEYROM 28 A SLICE_X36Y64 b'88825ff323665a51'
KEYROM 28 B SLICE_X36Y64 b'6e49b5862e6533ac'
KEYROM 28 C SLICE_X36Y64 b'32fed356801273ab'
KEYROM 28 D SLICE_X36Y64 b'37904b87d81a652a'
KEYROM 29 A SLICE_X37Y64 b'4b5361b16868f5bd'
KEYROM 29 B SLICE_X37Y64 b'ba9596094f9e43b9'
KEYROM 29 C SLICE_X37Y64 b'ddabe807f246ff41'
KEYROM 29 D SLICE_X37Y64 b'8815407bf7b4e684'
KEYROM 30 A SLICE_X36Y65 b'0165ea750602f2be'
KEYROM 30 B SLICE_X36Y65 b'3c62683258a88ef9'
KEYROM 30 C SLICE_X36Y65 b'cc0c02f8539bf6d8'
KEYROM 30 D SLICE_X36Y65 b'a1caffc2420bc6de'
KEYROM 31 A SLICE_X37Y65 b'2a2894ffa957b03c'
KEYROM 31 B SLICE_X37Y65 b'958c5490ad6c2e9b'
KEYROM 31 C SLICE_X37Y65 b'f76c75011cdc2737'
KEYROM 31 D SLICE_X37Y65 b'a734aab8e4d7f6eb'

View file

@ -3,7 +3,7 @@
<device schemaVersion="1.1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" >
<vendor>litex</vendor>
<name>SOC</name>
<description><![CDATA[Litex SoC 2021-07-20 21:53:20]]></description>
<description><![CDATA[Litex SoC 2021-08-06 13:55:31]]></description>
<addressUnitBits>8</addressUnitBits>
<width>32</width>
@ -1238,10 +1238,10 @@ register to disable individual events.]]></description>
<register>
<name>GIT_GITREV</name>
<description><![CDATA[First 32-bits of the git revision. This documentation was built from git rev
``e64c9cef``, so this value is 3863780591, which should be enough to check out
``890b90e7``, so this value is 2299236583, which should be enough to check out
the exact git version used to build this firmware.]]></description>
<addressOffset>0x0014</addressOffset>
<resetValue>0xe64c9cef</resetValue>
<resetValue>0x890b90e7</resetValue>
<size>32</size>
<fields>
<field>
@ -1258,7 +1258,7 @@ the exact git version used to build this firmware.]]></description>
is ``1``, then the repository this was built from has one additional commit
beyond the tag indicated in `MAJOR`, `MINOR`, and `REVISION`.]]></description>
<addressOffset>0x0018</addressOffset>
<resetValue>0x43</resetValue>
<resetValue>0x46</resetValue>
<size>32</size>
<fields>
<field>
@ -3584,7 +3584,7 @@ inject too fast.]]></description>
<name>SEED1</name>
<description><![CDATA[Bits 32-63 of `SEED_SEED`. Seed used for the build]]></description>
<addressOffset>0x0000</addressOffset>
<resetValue>0x19f188fb</resetValue>
<resetValue>0x4f340196</resetValue>
<size>32</size>
<fields>
<field>
@ -3599,7 +3599,7 @@ inject too fast.]]></description>
<name>SEED0</name>
<description><![CDATA[Bits 0-31 of `SEED_SEED`.]]></description>
<addressOffset>0x0004</addressOffset>
<resetValue>0x53401497</resetValue>
<resetValue>0x77c237e8</resetValue>
<size>32</size>
<fields>
<field>

Binary file not shown.

View file

@ -89,7 +89,6 @@ pub(crate) struct UxContext {
pub audioframe_id: Option<u32>,
}
const MAX_UX_CONTEXTS: usize = 6;
pub(crate) const MAX_CANVASES: usize = 32;
// const BOOT_APP_NAME: &'static str = "shellchat"; // this is the app to display on boot -- we will eventually need this once we have more than one app?
pub const ROOTKEY_MODAL_NAME: &'static str = "rootkeys modal";
const BOOT_CONTEXT_TRUSTLEVEL: u8 = 254;

View file

@ -54,10 +54,25 @@
"zh": "准备重启...",
"en-audio": "Preparing to reboot."
},
"rootkeys.init.failure": {
"en": "Process failed, aborting!",
"zh": "正在初始化失败,中止!",
"en-audio": "Process failed, aborting"
"rootkeys.init.fail_verify": {
"en": "Verification failed,\naborting!",
"zh": "*missing*正在初始化失败,中止!",
"en-audio": "Verification failed, aborting"
},
"rootkeys.init.fail_key": {
"en": "FPGA key is wrong,\nborting!",
"zh": "*missing*正在初始化失败,中止!",
"en-audio": "FPGA key is wrong, aborting"
},
"rootkeys.init.fail_burn": {
"en": "FLASH write problem,\naborting!",
"zh": "*missing*正在初始化失败,中止!",
"en-audio": "FLASH write problem, aborting"
},
"rootkeys.init.fail_alignment": {
"en": "Internal alignment error,\naborting!",
"zh": "*missing*正在初始化失败,中止!",
"en-audio": "Internal alignment error, aborting"
},
"rootkeys.init.confirmation": {
"en": "This cannot be undone.\nContinue?",

View file

@ -1,6 +1,7 @@
pub(crate) const SERVER_NAME_KEYS: &str = "_Root key server and update manager_";
#[allow(dead_code)]
pub(crate) const ROOTKEY_MODAL_NAME: &'static str = "rootkeys modal";
#[allow(dead_code)]
pub(crate) const ROOTKEY_MENU_NAME: &'static str = "rootkeys menu";
#[allow(dead_code)]
@ -9,6 +10,8 @@ pub(crate) enum Opcode {
/// use to check if we've been initialized
KeysInitialized,
TestUx,
/// attempt to initialize keys on a brand new system. Does nothing if the keys are already provisioned.
UxTryInitKeys,
UxInitRequestPassword,
@ -46,4 +49,12 @@ pub enum PasswordRetentionPolicy {
pub enum PasswordType {
Boot = 1,
Update = 2,
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum RootkeyResult {
AlignmentError,
KeyError,
IntegrityError,
FlashError,
}

View file

@ -1,7 +1,4 @@
use gam::FONT_TOTAL_LEN;
use ticktimer_server::Ticktimer;
use utralib::generated::*;
use xous::SOC_STAGING_GW_LEN;
use crate::api::*;
use core::num::NonZeroUsize;
use num_traits::*;
@ -13,7 +10,7 @@ use crate::bcrypt::*;
use crate::api::PasswordType;
use core::convert::TryInto;
use ed25519_dalek::{Keypair, Signature, Signer};
use ed25519_dalek::{Keypair, Signature};
use engine_sha512::*;
use digest::Digest;
use graphics_server::BulkRead;
@ -83,13 +80,6 @@ pub(crate) mod keyrom_config {
pub const INITIALIZED: KeyField = KeyField::new(1, 27);
}
enum RootkeyResult {
AlignmentError,
KeyError,
IntegrityError,
FlashError,
}
/// This structure is mapped into the password cache page and can be zero-ized at any time
/// we avoid using fancy Rust structures because everything has to "make sense" after a forced zero-ization
/// The "password" here is generated as follows:
@ -131,20 +121,32 @@ const AES_BLOCKSIZE: usize = 16;
/// stream from an arbitrary position.
struct BitstreamOracle<'a> {
bitstream: &'a [u8],
cipher: Aes256,
base: u32,
dec_cipher: Aes256,
enc_cipher: Aes256,
iv: [u8; AES_BLOCKSIZE],
/// subslice of the bitstream that contains just the encrypted area of the bitstream
ciphertext: &'a [u8],
ct_absolute_offset: usize,
type2_count: u32,
/// start of type2 data as an absolute offset in the overall bitstream
type2_absolute_offset: usize,
/// start of type2 data as an offset relative to the start of ciphertext
type2_ciphertext_offset: usize,
}
impl<'a> BitstreamOracle<'a> {
pub fn new(key: &'a[u8], bitstream: &'a[u8]) -> BitstreamOracle<'a> {
/// oracle supports separate encryption and decryption keys, so that it may
/// be used for re-encryption of bitstreams to a new key. If using it for patching,
/// set the keys to the same value.
pub fn new(dec_key: &'a[u8], enc_key: &'a[u8], bitstream: &'a[u8], base: u32) -> Result<BitstreamOracle<'a>, RootkeyResult> {
let mut position: usize = 0;
// Search through the bitstream for the key words that define the IV and ciphertetx length.
// This is done so that if extra headers are added or modified, the code doesn't break (versus coding in static offsets).
let mut iv_pos = 0;
let mut cwd = 0;
while position < bitstream.len() {
let cwd = u32::from_be_bytes(bitstream[position..position+4].try_into().unwrap());
cwd = u32::from_be_bytes(bitstream[position..position+4].try_into().unwrap());
if cwd == 0x3001_6004 {
iv_pos = position + 4
}
@ -157,6 +159,10 @@ impl<'a> BitstreamOracle<'a> {
let position = position + 4;
let ciphertext_len = 4 * u32::from_be_bytes(bitstream[position..position+4].try_into().unwrap());
let ciphertext_start = position + 4;
if ciphertext_start & (AES_BLOCKSIZE - 1) != 0 {
log::error!("Padding is incorrect on the bitstream. Check append_csr.py for padding and make sure you are burning gateware with --raw-binary, and not --bitstream as the latter strips padding from the top of the file.");
return Err(RootkeyResult::AlignmentError)
}
log::info!("ciphertext len: {} bytes, start: 0x{:08x}", ciphertext_len, ciphertext_start);
let ciphertext = &bitstream[ciphertext_start..ciphertext_start + ciphertext_len as usize];
@ -165,26 +171,93 @@ impl<'a> BitstreamOracle<'a> {
log::info!("recovered iv (pre-flip): {:x?}", &bitstream[iv_pos..iv_pos + AES_BLOCKSIZE]);
log::info!("recovered iv : {:x?}", &iv_bytes);
let cipher = Aes256::new(key.try_into().unwrap());
let dec_cipher = Aes256::new(dec_key.try_into().unwrap());
let enc_cipher = Aes256::new(enc_key.try_into().unwrap());
BitstreamOracle {
let mut oracle = BitstreamOracle {
bitstream,
cipher,
base,
dec_cipher,
enc_cipher,
iv: iv_bytes,
ciphertext,
ct_absolute_offset: ciphertext_start,
type2_count: 0,
type2_absolute_offset: 0,
type2_ciphertext_offset: 0,
};
// search forward for the "type 2" region in the first kilobyte of plaintext
// type2 is where regular dataframes start, and we can compute offsets for patching
// based on this.
let mut first_block: [u8; 1024] = [0; 1024];
oracle.decrypt(0, &mut first_block);
// check that the plaintext header has a well-known sequence in it -- sanity check the AES key
let mut pass = true;
for &b in first_block[32..64].iter() {
if b != 0x6C {
pass = false;
}
}
if !pass {
log::error!("hmac_header did not decrypt correctly: {:x?}", &first_block[..64]);
return Err(RootkeyResult::KeyError)
}
// start searching for the commands *after* the IV and well-known sequence
let mut pt_pos = 64;
let mut flipword: [u8; 4] = [0; 4];
for word in first_block[64..].chunks_exact(4).into_iter() {
bitflip(&word[0..4], &mut flipword);
cwd = u32::from_be_bytes(flipword);
pt_pos += 4;
if (cwd & 0xE000_0000) == 0x4000_0000 {
break;
}
}
oracle.type2_count = cwd & 0x3FF_FFFF;
if pt_pos > 1000 { // pt_pos is usually found within the first 200 bytes of a bitstream, should definitely be in the first 1k or else shenanigans
log::error!("type 2 region not found in the expected region, is the FPGA key correct?");
return Err(RootkeyResult::KeyError)
}
oracle.type2_absolute_offset = pt_pos + ciphertext_start;
oracle.type2_ciphertext_offset = pt_pos;
log::info!("type2 absolute: {}, relative to ct start: {}", oracle.type2_absolute_offset, oracle.type2_ciphertext_offset);
Ok(oracle)
}
pub fn base(&self) -> u32 {self.base}
pub fn ciphertext_offset(&self) -> usize {
self.ct_absolute_offset as usize
}
pub fn ciphertext(&self) -> &[u8] {
self.ciphertext
}
pub fn ciphertext_offset_to_frame(&self, offset: usize) -> (usize, usize) {
let type2_offset = offset - self.type2_ciphertext_offset;
let frame = type2_offset / (101 * 4);
let frame_offset = type2_offset - (frame * 101 * 4);
(frame, frame_offset / 4)
}
pub fn clear(&mut self) {
self.cipher.clear();
self.enc_cipher.clear();
self.dec_cipher.clear();
}
/// decrypts a portion of the bitstream starting at "from", of length output
pub fn decrypt(&self, from: usize, output: &mut [u8]) {
/// Decrypts a portion of the bitstream starting at "from", of length output.
/// Returns the actual number of bytes processed.
pub fn decrypt(&self, from: usize, output: &mut [u8]) -> usize {
assert!(from & (AES_BLOCKSIZE - 1) == 0); // all requests must be an even multiple of an AES block size
let mut index = from;
let mut temp_block = [0; AES_BLOCKSIZE];
let mut chain: [u8; AES_BLOCKSIZE] = [0; AES_BLOCKSIZE];
let mut bytes_processed = 0;
for block in output.chunks_mut(AES_BLOCKSIZE).into_iter() {
if index > self.ciphertext_len() - AES_BLOCKSIZE {
return bytes_processed;
}
if index == 0 {
chain = self.iv;
} else {
@ -195,7 +268,7 @@ impl<'a> BitstreamOracle<'a> {
// replaces the ciphertext with "plaintext"
let mut d = GenericArray::clone_from_slice(&mut temp_block);
self.cipher.decrypt_block(&mut d);
self.dec_cipher.decrypt_block(&mut d);
for (&src, dst) in d.iter().zip(temp_block.iter_mut()) {
*dst = src;
}
@ -207,28 +280,106 @@ impl<'a> BitstreamOracle<'a> {
*dst = src ^ iv;
}
index += AES_BLOCKSIZE;
bytes_processed += AES_BLOCKSIZE;
}
bytes_processed
}
/// Encrypts a portion of a bitstream starting at "from"; manages the IV lookup for the encryption process
///
/// "from" is relative to ciphertext start, and chosen to match the "from" of a decrypt operation.
/// When using this function to encrypt the very first block, the "from" offset should be negative.
///
/// ASSUME: the chain is unbroken, e.g. this is being called successively on correctly encrypted, chained
/// blocks, that have been written to FLASH such that we can refer to the older blocks for the current
/// chaining value. It is up to the caller to manage the linear order of the calls.
/// ASSUME: `from` + `self.ct_absolute_offset` is a multiple of an erase block
/// returns the actual number of bytes processed
pub fn encrypt_sector(&self, from: i32, input_plaintext: &[u8], output_sector: &mut [u8]) -> usize {
assert!(output_sector.len() & (AES_BLOCKSIZE - 1) == 0, "output length must be a multiple of AES block size");
assert!(input_plaintext.len() & (AES_BLOCKSIZE - 1) == 0, "input length must be a multiple of AES block size");
assert!((from + self.ct_absolute_offset as i32) & (spinor::SPINOR_ERASE_SIZE as i32 - 1) == 0, "request address must line up with an erase block boundary");
if from > 0 {
assert!(input_plaintext.len() == output_sector.len(), "input and output length must match");
} else {
assert!(input_plaintext.len() == output_sector.len() - self.ct_absolute_offset, "output length must have space for the plaintext header");
}
let mut out_start_offset = 0;
if from < 0 {
// copy the plaintext header as-is: we don't modify it, once it's in the device (e.g. we won't switch
// from eFuse to BBRAM or back again). Later on if such a switching is desired, I believe it's just a couple
// bytes patched in the plaintext header to change this, but, for now, let's assume once you're on a given
// encryption train, you're staying on it. BBRAM requires external provisioning anyways, and BBRAM users
// would be using this feature because they don't trust eFuse. eFuse users can't switch to BBRAM without an
// external programmer that would burn the key in the first place.
// the plaintext header already has:
// - all the fuse and config settings
// - padding
// - IV for cipher
// - length of ciphertext region
for (&src, dst) in self.bitstream[..self.ct_absolute_offset].iter()
.zip(output_sector[..self.ct_absolute_offset].iter_mut()) {
*dst = src;
}
out_start_offset = self.ct_absolute_offset;
}
let mut chain: [u8; AES_BLOCKSIZE] = self.iv;
if from > 0 {
bitflip(&self.ciphertext[from as usize - AES_BLOCKSIZE..from as usize], &mut chain);
}
let mut bytes_processed = 0;
let mut temp_block = [0; AES_BLOCKSIZE];
for (iblock, oblock) in input_plaintext.chunks(AES_BLOCKSIZE).into_iter()
.zip(output_sector[out_start_offset..].chunks_mut(AES_BLOCKSIZE).into_iter()) {
// XOR against IV/chain value
for (dst, (&src, &iv)) in temp_block.iter_mut().zip(iblock.iter().zip(chain.iter())) {
*dst = src ^ iv;
}
let mut e = GenericArray::clone_from_slice(&mut temp_block);
self.enc_cipher.encrypt_block(&mut e);
for (&src, dst) in e.iter().zip(temp_block.iter_mut()) {
*dst = src;
}
// redo the IV based on the previous output. no bitflipping of the IV.
for (&src, dst) in temp_block.iter().zip(chain.iter_mut()) {
*dst = src;
}
// copy the ciphertext into the output block, with a bitflip
bitflip(&temp_block, oblock);
bytes_processed += AES_BLOCKSIZE;
}
bytes_processed
}
pub fn ciphertext_len(&self) -> usize {
self.ciphertext.len()
}
}
/*
impl<'a> Drop for BitstreamOracle<'a> {
fn drop(&mut self) {
self.cipher.clear();
self.enc_cipher.clear();
self.dec_cipher.clear();
for b in self.iv.iter_mut() {
*b = 0;
}
core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
}
}
}*/
pub(crate) struct RootKeys {
keyrom: utralib::CSR<u32>,
gateware: xous::MemoryRange,
staging: xous::MemoryRange,
loader_code: xous::MemoryRange,
kernel: xous::MemoryRange,
gateware_mr: xous::MemoryRange,
gateware_base: u32,
staging_mr: xous::MemoryRange,
staging_base: u32,
loader_code_mr: xous::MemoryRange,
loader_code_base: u32,
kernel_mr: xous::MemoryRange,
kernel_base: u32,
/// regions of RAM that holds all plaintext passwords, keys, and temp data. stuck in two well-defined page so we can
/// zero-ize it upon demand, without guessing about stack frames and/or Rust optimizers removing writes
sensitive_data: xous::MemoryRange, // this gets purged at least on every suspend, but ideally purged sooner than that
@ -238,10 +389,10 @@ pub(crate) struct RootKeys {
cur_password_type: Option<PasswordType>, // for tracking which password we're dealing with at the UX layer
susres: susres::Susres, // for disabling suspend/resume
trng: trng::Trng,
gam: gam::Gam, // for raising UX elements directly
//gam: gam::Gam, // for raising UX elements directly
gfx: graphics_server::Gfx, // for reading out font planes for signing verification
spinor: spinor::Spinor,
ticktimer: ticktimer_server::Ticktimer,
//ticktimer: ticktimer_server::Ticktimer,
}
impl RootKeys {
@ -298,10 +449,14 @@ impl RootKeys {
let keys = RootKeys {
keyrom: CSR::new(keyrom.as_mut_ptr() as *mut u32),
gateware,
staging,
loader_code,
kernel,
gateware_mr: gateware,
gateware_base: xous::SOC_MAIN_GW_LOC,
staging_mr: staging,
staging_base: xous::SOC_STAGING_GW_LOC,
loader_code_mr: loader_code,
loader_code_base: xous::LOADER_LOC,
kernel_mr: kernel,
kernel_base: xous::KERNEL_LOC,
sensitive_data,
pass_cache,
update_password_policy: PasswordRetentionPolicy::AlwaysPurge,
@ -309,14 +464,30 @@ impl RootKeys {
cur_password_type: None,
susres: susres::Susres::new_without_hook(&xns).expect("couldn't connect to susres without hook"),
trng: trng::Trng::new(&xns).expect("couldn't connect to TRNG server"),
gam: gam::Gam::new(&xns).expect("couldn't connect to GAM"),
//gam: gam::Gam::new(&xns).expect("couldn't connect to GAM"),
gfx: graphics_server::Gfx::new(&xns).expect("couldn't connect to gfx"),
spinor,
ticktimer: ticktimer_server::Ticktimer::new().expect("couldn't connect to ticktimer"),
//ticktimer: ticktimer_server::Ticktimer::new().expect("couldn't connect to ticktimer"),
};
keys
}
pub fn gateware(&self) -> &[u8] {
self.gateware_mr.as_slice::<u8>()
}
pub fn gateware_base(&self) -> u32 { self.gateware_base }
pub fn staging(&self) -> &[u8] {
self.staging_mr.as_slice::<u8>()
}
pub fn staging_base(&self) -> u32 { self.staging_base }
pub fn loader_code(&self) -> &[u8] {
self.loader_code_mr.as_slice::<u8>()
}
pub fn loader_base(&self) -> u32 { self.loader_code_base }
pub fn kernel(&self) -> &[u8] {
self.kernel_mr.as_slice::<u8>()
}
pub fn kernel_base(&self) -> u32 { self.kernel_base }
fn purge_password(&mut self, pw_type: PasswordType) {
unsafe {
@ -545,11 +716,49 @@ impl RootKeys {
/// - get ready for a reboot
/// - returns true if we should reboot (everything succeeded)
/// - returns false if we had an error condition (don't reboot)
pub fn do_key_init(&mut self, progress_modal: &mut Modal, progress_action: &mut Slider) -> bool {
pub fn do_key_init(&mut self, progress_modal: &mut Modal, progress_action: &mut Slider) -> Result<(), RootkeyResult> {
// kick the progress bar to indicate we've entered the routine
update_progress(1, progress_modal, progress_action);
// get access to the pcache and generate a keypair
let pcache: &mut PasswordCache = unsafe{&mut *(self.pass_cache.as_mut_ptr() as *mut PasswordCache)};
let keypair: Keypair = Keypair::generate(&mut self.trng);
// encrypt the FPGA key using the update password. in an un-init system, it is provided to us in plaintext format
// e.g. in the case that we're doing a BBRAM boot (eFuse flow would give us a 0's key and we'd later on set it)
#[cfg(feature = "hazardous-debug")]
self.debug_print_key(KeyRomLocs::FPGA_KEY as usize, 256, "FPGA key before encryption: ");
{
let sensitive_slice = self.sensitive_data.as_slice_mut::<u32>();
// before we encrypt it, stash a copy in our password cache, as we'll need it later on to encrypt the bitstream
for (word, key) in sensitive_slice[KeyRomLocs::FPGA_KEY as usize..KeyRomLocs::FPGA_KEY as usize + 256/(size_of::<u32>()*8)].iter()
.zip(pcache.fpga_key.chunks_mut(4).into_iter()) {
for (&s, d) in word.to_be_bytes().iter().zip(key.iter_mut()) {
*d = s;
}
}
pcache.fpga_key_valid = 1;
// now encrypt it in the staging area
for (word, key_word) in sensitive_slice[KeyRomLocs::FPGA_KEY as usize..KeyRomLocs::FPGA_KEY as usize + 256/(size_of::<u32>()*8)].iter_mut()
.zip(pcache.hashed_update_pw.chunks(4).into_iter()) {
*word = *word ^ u32::from_be_bytes(key_word.try_into().unwrap());
}
}
// allocate a decryption oracle for the FPGA bitstream. This will fail early if the FPGA key is wrong.
assert!(pcache.fpga_key_valid == 1);
// note to self: BitstreamOracle implements Drop which will clear the key schedule and iv
let mut dst_oracle = match BitstreamOracle::new(&pcache.fpga_key, &pcache.fpga_key, self.gateware(), self.gateware_base()) {
Ok(o) => o,
Err(e) => {
log::error!("couldn't create oracle (most likely FPGA key mismatch): {:?}", e);
return Err(e);
}
};
update_progress(5, progress_modal, progress_action);
// pub key is easy, no need to encrypt
let public_key: [u8; ed25519_dalek::PUBLIC_KEY_LENGTH] = keypair.public.to_bytes();
{ // scope sensitive_slice narrowly, as it borrows *self mutably, and can mess up later calls that borrow an immutable self
@ -562,7 +771,6 @@ impl RootKeys {
}
// extract the update password key from the cache, and apply it to the private key
let pcache: &mut PasswordCache = unsafe{&mut *(self.pass_cache.as_mut_ptr() as *mut PasswordCache)};
#[cfg(feature = "hazardous-debug")]
{
log::info!("cached boot passwords {:x?}", pcache.hashed_boot_pw);
@ -587,7 +795,7 @@ impl RootKeys {
}
}
update_progress(5, progress_modal, progress_action);
update_progress(10, progress_modal, progress_action);
// generate and store a root key (aka boot key), this is what is unlocked by the "boot password"
// ironically, it's a "lower security" key because it just acts as a gatekeeper to further
@ -619,7 +827,7 @@ impl RootKeys {
// sign the loader
progress_modal.modify(None, Some(t!("rootkeys.init.signing_loader", xous::LANG)), false, None, false, None);
update_progress(10, progress_modal, progress_action);
update_progress(15, progress_modal, progress_action);
let (loader_sig, loader_len) = self.sign_loader(&keypair);
// sign the kernel
@ -628,34 +836,10 @@ impl RootKeys {
let (kernel_sig, kernel_len) = self.sign_kernel(&keypair);
update_progress(25, progress_modal, progress_action);
// encrypt the FPGA key using the update password. in an un-init system, it is provided to us in plaintext format
// e.g. in the case that we're doing a BBRAM boot (eFuse flow would give us a 0's key and we'd later on set it)
#[cfg(feature = "hazardous-debug")]
self.debug_print_key(KeyRomLocs::FPGA_KEY as usize, 256, "FPGA key before encryption: ");
{
let sensitive_slice = self.sensitive_data.as_slice_mut::<u32>();
// before we encrypt it, stash a copy in our password cache, as we'll need it later on to encrypt the bitstream
for (word, key) in sensitive_slice[KeyRomLocs::FPGA_KEY as usize..KeyRomLocs::FPGA_KEY as usize + 256/(size_of::<u32>()*8)].iter()
.zip(pcache.fpga_key.chunks_mut(4).into_iter()) {
for (&s, d) in word.to_be_bytes().iter().zip(key.iter_mut()) {
*d = s;
}
}
pcache.fpga_key_valid = 1;
// now encrypt it in the staging area
for (word, key_word) in sensitive_slice[KeyRomLocs::FPGA_KEY as usize..KeyRomLocs::FPGA_KEY as usize + 256/(size_of::<u32>()*8)].iter_mut()
.zip(pcache.hashed_update_pw.chunks(4).into_iter()) {
*word = *word ^ u32::from_be_bytes(key_word.try_into().unwrap());
}
}
update_progress(30, progress_modal, progress_action);
// set the "init" bit in the staging area
{
let sensitive_slice = self.sensitive_data.as_slice_mut::<u32>();
self.keyrom.wfo(utra::keyrom::ADDRESS_ADDRESS, KeyRomLocs::CONFIG as u32);
let config = self.keyrom.rf(utra::keyrom::DATA_DATA);
sensitive_slice[KeyRomLocs::CONFIG as usize] |= keyrom_config::INITIALIZED.ms(1);
}
@ -670,43 +854,53 @@ impl RootKeys {
// the staging area. Note that if we're doing an update, the update target would already be
// in the staging area, so this step should be skipped.
progress_modal.modify(None, Some(t!("rootkeys.init.backup_gateware", xous::LANG)), false, None, false, None);
update_progress(40, progress_modal, progress_action);
if self.make_gateware_backup(40, 60, progress_modal, progress_action).is_err() {
log::error!("error occured in make_gateware_backup.");
return false;
update_progress(30, progress_modal, progress_action);
self.make_gateware_backup(30, 50, progress_modal, progress_action)?;
let mut src_oracle = match BitstreamOracle::new(&pcache.fpga_key, &pcache.fpga_key, self.staging(), self.staging_base()) {
Ok(o) => o,
Err(e) => {
log::error!("couldn't create oracle (most likely FPGA key mismatch): {:?}", e);
return Err(e);
}
};
// compute the keyrom patch set for the bitstream
// at this point the KEYROM as replicated in sensitive_slice should have all its assets in place
progress_modal.modify(None, Some(t!("rootkeys.init.patching_keys", xous::LANG)), false, None, false, None);
update_progress(60, progress_modal, progress_action);
update_progress(50, progress_modal, progress_action);
let gateware = self.gateware.as_slice::<u8>();
assert!(pcache.fpga_key_valid == 1);
// note to self: BitstreamOracle implements Drop which will clear the key schedule and iv
let oracle = BitstreamOracle::new(&pcache.fpga_key, gateware);
if self.patch_keys(&oracle, 60, 70, progress_modal, progress_action).is_err() {
log::error!("error occured in patch_keys.");
return false;
}
patch::should_patch(42);
self.gateware_copy_and_patch(&src_oracle, &dst_oracle, 50, 70, progress_modal, progress_action)?;
// verify that the patch worked
progress_modal.modify(None, Some(t!("rootkeys.init.verifying_gateware", xous::LANG)), false, None, false, None);
self.verify_gateware(&dst_oracle, 70, 90, progress_modal, progress_action)?;
update_progress(90, progress_modal, progress_action);
// --> put the verify call here
// sign the image, commit the signature
// --> add something to sign the gateware region here
// --> format the signatures and write them to FLASH
//////// this is 90%-100% task
// these implement drop so they should implicitly clear, but -- doesn't hurt to call it explicitly
src_oracle.clear();
dst_oracle.clear();
// finalize the progress bar on exit -- always leave at 100%
progress_modal.modify(None, Some(t!("rootkeys.init.finished", xous::LANG)), false, None, false, None);
update_progress(100, progress_modal, progress_action);
true
Ok(())
}
pub fn printkeys(&mut self) {
// setup the local cache
let sensitive_slice = self.sensitive_data.as_slice_mut::<u32>();
for addr in 0..256 {
self.keyrom.wfo(utra::keyrom::ADDRESS_ADDRESS, addr);
sensitive_slice[addr as usize] = self.keyrom.rf(utra::keyrom::DATA_DATA);
log::info!("{:02x}: 0x{:08x}", addr, sensitive_slice[addr as usize]);
}
}
pub fn test(&mut self, progress_modal: &mut Modal, progress_action: &mut Slider) -> bool {
@ -717,6 +911,7 @@ impl RootKeys {
for addr in 0..256 {
self.keyrom.wfo(utra::keyrom::ADDRESS_ADDRESS, addr);
sensitive_slice[addr as usize] = self.keyrom.rf(utra::keyrom::DATA_DATA);
log::info!("{:02x}: 0x{:08x}", addr, sensitive_slice[addr as usize]);
}
for (word, key) in sensitive_slice[KeyRomLocs::FPGA_KEY as usize..KeyRomLocs::FPGA_KEY as usize + 256/(size_of::<u32>()*8)].iter()
@ -726,19 +921,36 @@ impl RootKeys {
}
}
pcache.fpga_key_valid = 1;
sensitive_slice[KeyRomLocs::CONFIG as usize] |= keyrom_config::INITIALIZED.ms(1);
sensitive_slice[0x30] = 0xc0de_600d;
sensitive_slice[0x31] = 0x1234_5678;
sensitive_slice[0x32] = 0x8000_0000;
sensitive_slice[0x33] = 0x5555_3333;
// make the oracle
let gateware = self.gateware.as_slice::<u8>();
// one time only
/*
match self.make_gateware_backup(30, 50, progress_modal, progress_action) {
Err(e) => {
log::error!("got spinor error: {:?}", e);
panic!("got spinor error, halting");
}
_ => ()
};*/
// make the oracles
assert!(pcache.fpga_key_valid == 1);
let oracle = BitstreamOracle::new(&pcache.fpga_key, gateware);
// copy from staging
let src_oracle = BitstreamOracle::new(&pcache.fpga_key, &pcache.fpga_key, self.staging(), self.staging_base()).unwrap();
// write to gateware
let dst_oracle = BitstreamOracle::new(&pcache.fpga_key, &pcache.fpga_key, self.gateware(), self.gateware_base()).unwrap();
// TEST
if self.patch_keys(&oracle, 60, 80, progress_modal, progress_action).is_err() {
if self.gateware_copy_and_patch(&src_oracle, &dst_oracle, 60, 80, progress_modal, progress_action).is_err() {
log::error!("error occured in patch_keys.");
return false;
}
if self.verify_gateware(&oracle, 80, 100, progress_modal, progress_action).is_err() {
if self.verify_gateware(&dst_oracle, 80, 100, progress_modal, progress_action).is_err() {
log::error!("error occurred in gateware verification");
return false;
}
@ -748,34 +960,233 @@ impl RootKeys {
true
}
fn patch_keys(&self, oracle: &BitstreamOracle, prog_start: u32, prog_end: u32, progress_modal: &mut Modal, progress_action: &mut Slider) -> Result<(), RootkeyResult> {
/// copy data from a source region to a destination region, re-encrypting and patching as we go along.
/// the region/region_base should be specified for the destination oracle
///
/// KEYROM patching data must previously have been staged in the sensitive area.
/// failure to do so would result in the erasure of all secret data.
/// ASSUME: CSR appendix does not change during the copy (it is not copied/updated)
fn gateware_copy_and_patch(&self, src_oracle: &BitstreamOracle, dst_oracle: &BitstreamOracle,
prog_start: u32, prog_end: u32, progress_modal: &mut Modal, progress_action: &mut Slider) -> Result<(), RootkeyResult> {
let mut last_prog_update = 0;
// extract the HMAC header
let mut hmac_header: [u8; 64] = [0; 64];
oracle.decrypt(0, &mut hmac_header);
// check that the header has a well-known sequence in it -- sanity check the AES key
let mut pass = true;
for &b in hmac_header[32..].iter() {
if b != 0x6C {
pass = false;
}
}
if !pass {
log::error!("hmac_header did not decrypt correctly: {:x?}", hmac_header);
let sensitive_slice = self.sensitive_data.as_slice_mut::<u32>();
if sensitive_slice[KeyRomLocs::CONFIG as usize] & keyrom_config::INITIALIZED.ms(1) == 0 {
// the keys weren't initialized, or are wrong. abort!
return Err(RootkeyResult::KeyError);
}
log::info!("sanity checks: src_offset {}, dst_offset {}, src_len {}, dst_len {}",
src_oracle.ciphertext_offset(), dst_oracle.ciphertext_offset(), src_oracle.ciphertext_len(), dst_oracle.ciphertext_len());
// patch the keyrom frames
for frame in patch::PATCH_FRAMES.iter() {
// start with a naive implementation that simple goes through and re-encrypts and patches everything.
// later on, we could skip patching everything up to the first frame that needs patching;
// this should optimize up to 15% of the time required to do a patch, although, because the patching
// routine is "smart" and does not issue writes for unchanged data, this could actually be a much
// smaller performance gain.
let mut pt_sector: [u8; spinor::SPINOR_ERASE_SIZE as usize] = [0; spinor::SPINOR_ERASE_SIZE as usize];
let mut ct_sector: [u8; spinor::SPINOR_ERASE_SIZE as usize] = [0; spinor::SPINOR_ERASE_SIZE as usize];
let mut flipper: [u8; spinor::SPINOR_ERASE_SIZE as usize] = [0; spinor::SPINOR_ERASE_SIZE as usize];
let mut hasher = engine_sha512::Sha256::new();
let hash_stop = src_oracle.ciphertext_len() - 320 - 160;
// handle the special case of the first sector
src_oracle.decrypt(0, &mut pt_sector);
// initialize the hmac code for later use
let mut hmac_code: [u8; 32] = [0; 32];
for (dst, (&hm1, &mask)) in
hmac_code.iter_mut()
.zip(pt_sector[0..32].iter().zip(pt_sector[32..64].iter())) {
*dst = hm1 ^ mask;
}
log::info!("recovered hmac: {:x?}", hmac_code);
// hash the decrypt data; we assume we're not patching anything in the first sector.
let mut bytes_hashed = spinor::SPINOR_ERASE_SIZE as usize - src_oracle.ciphertext_offset();
bitflip(&pt_sector[..bytes_hashed], &mut flipper[..bytes_hashed]);
hasher.update(&flipper[..bytes_hashed]);
// now encrypt and patch the data to disk
dst_oracle.encrypt_sector(
-(dst_oracle.ciphertext_offset() as i32),
&pt_sector[..bytes_hashed],
&mut ct_sector // full array, for space for plaintext header
);
log::info!("sector 0 patch len: {}", bytes_hashed);
self.spinor.patch(dst_oracle.bitstream, dst_oracle.base, &ct_sector, 0)
.map_err(|_| RootkeyResult::FlashError)?;
// now we can patch the rest of the sectors as a loop
let mut from = spinor::SPINOR_ERASE_SIZE - src_oracle.ciphertext_offset() as u32;
let mut dummy_consume = 0;
let max_step = src_oracle.ciphertext[from as usize..].chunks(spinor::SPINOR_ERASE_SIZE as usize).into_iter().count();
for (step, _) in src_oracle.ciphertext[from as usize..].chunks(spinor::SPINOR_ERASE_SIZE as usize).into_iter().enumerate() {
let decrypt_len = src_oracle.decrypt(from as usize, &mut pt_sector);
// wrap the patch call with a range check, because the patch lookup search is pretty expensive
if self.patch_in_range(src_oracle, from, from + spinor::SPINOR_ERASE_SIZE as u32) {
dummy_consume ^= self.patch_sector(src_oracle, from, &mut pt_sector, &sensitive_slice[0..256]);
}
let hash_len = if bytes_hashed + decrypt_len < hash_stop {
decrypt_len
} else {
hash_stop - bytes_hashed
};
if hash_len > 0 {
bitflip(&pt_sector[..hash_len], &mut flipper[..hash_len]);
hasher.update(&flipper[..hash_len]);
bytes_hashed += hash_len;
if hash_len != decrypt_len {
log::info!("final short block len: {}", hash_len);
}
}
dst_oracle.encrypt_sector(
from as i32,
&pt_sector[..decrypt_len],
&mut ct_sector[..decrypt_len],
);
self.spinor.patch(dst_oracle.bitstream, dst_oracle.base,
&ct_sector[..decrypt_len], from + dst_oracle.ciphertext_offset() as u32)
.map_err(|_| RootkeyResult::FlashError)?;
from += decrypt_len as u32;
let progress = ((prog_end - prog_start) * step as u32) / max_step as u32;
if progress != last_prog_update {
last_prog_update = progress;
update_progress(progress + prog_start, progress_modal, progress_action);
}
}
// consume the dummy value, to ensure it's not optimized out by the compiler
log::info!("copy_and_patch dummy consume: 0x{:x}", dummy_consume);
// at this point, we've patched & encrypted all the sectors, but we've
// encrypted the wrong hash at the end, so the HMAC won't work out. let's patch that.
let h1_digest: [u8; 32] = hasher.finalize().try_into().unwrap();
log::info!("bytes hashed: {}, computed h1 hash: {:x?}", bytes_hashed, h1_digest);
let mut hasher2 = engine_sha512::Sha256::new();
let footer_mask: [u8; 32] = [0x3A; 32];
let mut masked_footer: [u8; 32] = [0; 32];
for (dst, (&hm2, &mask)) in
masked_footer.iter_mut()
.zip(hmac_code.iter().zip(footer_mask.iter())) {
*dst = hm2 ^ mask;
}
log::info!("masked_footer: {:x?}", masked_footer);
log::info!("footer_mask: {:x?}", footer_mask);
let mut masked_footer_flipped: [u8; 32] = [0; 32];
bitflip(&masked_footer, &mut masked_footer_flipped);
let mut footer_mask_flipped: [u8; 32] = [0; 32];
bitflip(&footer_mask, &mut footer_mask_flipped);
hasher2.update(masked_footer_flipped);
hasher2.update(footer_mask_flipped);
hasher2.update(h1_digest);
let h2_digest: [u8; 32] = hasher2.finalize().try_into().unwrap();
log::info!("h2 hash: {:x?}", h2_digest);
// now encrypt and patch this final hashed value into the expected area
let ct_end = dst_oracle.ciphertext_len();
// the math below will have some problems if the block happens to end up exactly on an erase block boundary.
// but it doesn't, so I'm going to leave that case unaddressed...
let ct_last_block_loc = (ct_end & !(spinor::SPINOR_ERASE_SIZE as usize - 1)) - dst_oracle.ciphertext_offset();
let pt_sector_len = ct_end - ct_last_block_loc;
log::info!("ct_end: {}, ct_last_block_loc {}, pt_sector_len {}", ct_end, ct_last_block_loc, pt_sector_len);
src_oracle.decrypt(ct_last_block_loc, &mut pt_sector[..pt_sector_len]);
let mut temp = ct_last_block_loc;
for block in pt_sector[..pt_sector_len].chunks(32).into_iter() {
log::info!("{:x}: {:x?}", temp, block);
temp += 32;
}
//log::info!("last bytes: {:x?}", &pt_sector[pt_sector_len-256..pt_sector_len]);
// patch in the hash at the very end
let mut h2_digest_flipped: [u8; 32] = [0; 32];
bitflip(&h2_digest, &mut h2_digest_flipped);
for (&src, dst) in h2_digest_flipped.iter()
.zip(pt_sector[pt_sector_len - 32..pt_sector_len].iter_mut()) {
*dst = src;
}
log::info!("last bytes patched: {:x?}", &pt_sector[pt_sector_len-256..pt_sector_len]);
dst_oracle.encrypt_sector(ct_last_block_loc as i32, &pt_sector[..pt_sector_len], &mut ct_sector[..pt_sector_len]);
log::info!("hash patching from 0x{:x} len {}", ct_last_block_loc, pt_sector_len);
self.spinor.patch(dst_oracle.bitstream, dst_oracle.base,
&ct_sector[..pt_sector_len], ct_last_block_loc as u32 + dst_oracle.ciphertext_offset() as u32)
.map_err(|_| RootkeyResult::FlashError)?;
// read back for debug
log::info!("debug readback");
let dl = dst_oracle.decrypt(ct_last_block_loc, &mut pt_sector);
let mut temp = ct_last_block_loc;
for block in pt_sector[..dl].chunks(32).into_iter() {
log::info!("{:x}: {:x?}", temp, block);
temp += 32;
}
log::info!("dl: {} tl: {}", dl, dst_oracle.ciphertext_len());
let dl = dst_oracle.decrypt(0, &mut pt_sector);
let mut temp = 0;
for block in pt_sector[..dl].chunks(32).into_iter() {
log::info!("{:x}: {:x?}", temp, block);
temp += 32;
}
let dl = dst_oracle.decrypt(4096, &mut pt_sector);
let mut temp = 4096;
for block in pt_sector[..dl].chunks(32).into_iter() {
log::info!("{:x}: {:x?}", temp, block);
temp += 32;
}
// now seek to the various frames and patch their data...
Ok(())
}
fn patch_in_range(&self, oracle: &BitstreamOracle, range_ct_start: u32, range_ct_end: u32) -> bool {
let (start_frame, _) = oracle.ciphertext_offset_to_frame(range_ct_start as usize);
let (end_frame, _) = oracle.ciphertext_offset_to_frame(range_ct_end as usize);
if end_frame < patch::PATCH_FRAMES[0] as usize || start_frame > *patch::PATCH_FRAMES.last().unwrap() as usize {
false
} else {
true
}
}
// data_ct_start is the ciphertext offset of the region we're searching for a patch in
fn patch_sector(&self, oracle: &BitstreamOracle, data_ct_start: u32, data: &mut [u8], keyrom: &[u32]) -> u32 {
assert!(keyrom.len() == 256, "KEYROM data is not whole");
let mut dummy_consume = 0;
for (offset, word) in data.chunks_mut(4).into_iter().enumerate() {
let ct_offset = data_ct_start as usize + offset * 4;
let (frame, frame_offset) = oracle.ciphertext_offset_to_frame(ct_offset);
// the outer should_patch() call is a small optimization that replaces an O(N) search through
// a frame array with a pair of limit comparisons.
if patch::should_patch(frame as u32) {
match patch::patch_frame(frame as u32, frame_offset as u32, keyrom) {
Some((patch, patch_inv)) => {
let mut flip: [u8; 4] = [0; 4];
bitflip(&patch.to_be_bytes(), &mut flip);
log::info!("patching {} frame 0x{:x} offset {} 0x{:x} -> 0x{:x}", ct_offset, frame, frame_offset,
u32::from_be_bytes(word[0..4].try_into().unwrap()), u32::from_be_bytes(flip));
for (&s, d) in flip.iter().zip(word.iter_mut()) {
*d = s;
}
//log::info!("patched 0x{:x}", u32::from_be_bytes(word[0..4].try_into().unwrap()));
dummy_consume ^= patch_inv; // consume the dummy value (to keep constant time properties)
}
None => {}
}
}
}
dummy_consume
}
fn verify_gateware(&self, oracle: &BitstreamOracle, prog_start: u32, prog_end: u32, progress_modal: &mut Modal, progress_action: &mut Slider) -> Result<(), RootkeyResult> {
let mut last_prog_update = 0;
@ -787,7 +1198,7 @@ impl RootKeys {
.zip(hmac_area[0..32].iter().zip(hmac_area[32..64].iter())) {
*dst = hm1 ^ mask;
}
log::trace!("hmac code: {:x?}", hmac_code);
log::info!("hmac code: {:x?}", hmac_code);
log::debug!("verifying gateware");
let mut hasher = engine_sha512::Sha256::new();
@ -812,7 +1223,7 @@ impl RootKeys {
}
}
let h1_digest: [u8; 32] = hasher.finalize().try_into().unwrap();
log::trace!("computed hash: {:x?}", h1_digest);
log::info!("computed hash of {} bytes: {:x?}", tot_len, h1_digest);
let mut hasher2 = engine_sha512::Sha256::new();
let footer_mask: [u8; 32] = [0x3A; 32];
@ -822,8 +1233,8 @@ impl RootKeys {
.zip(hmac_code.iter().zip(footer_mask.iter())) {
*dst = hm2 ^ mask;
}
log::debug!("masked_footer: {:x?}", masked_footer);
log::debug!("footer_mask: {:x?}", footer_mask);
log::info!("masked_footer: {:x?}", masked_footer);
log::info!("footer_mask: {:x?}", footer_mask);
let mut masked_footer_flipped: [u8; 32] = [0; 32];
bitflip(&masked_footer, &mut masked_footer_flipped);
let mut footer_mask_flipped: [u8; 32] = [0; 32];
@ -833,13 +1244,13 @@ impl RootKeys {
hasher2.update(h1_digest);
let h2_digest: [u8; 32] = hasher2.finalize().try_into().unwrap();
log::debug!("h2 hash: {:x?}", h2_digest);
log::info!("h2 hash: {:x?}", h2_digest);
let mut ref_digest_flipped: [u8; 32] = [0; 32];
oracle.decrypt(oracle.ciphertext_len() - 32, &mut ref_digest_flipped);
let mut ref_digest: [u8; 32] = [0; 32];
log::debug!("ref digest (flipped): {:x?}", ref_digest_flipped);
log::info!("ref digest (flipped): {:x?}", ref_digest_flipped);
bitflip(&ref_digest_flipped, &mut ref_digest);
log::debug!("ref digest : {:x?}", ref_digest);
log::info!("ref digest : {:x?}", ref_digest);
let mut matching = true;
for (&l, &r) in ref_digest.iter().zip(h2_digest.iter()) {
@ -849,32 +1260,36 @@ impl RootKeys {
}
if matching {
log::info!("gateware verified");
Ok(())
} else {
log::info!("gateware failed to verify");
Err(RootkeyResult::IntegrityError)
}
}
fn make_gateware_backup(&mut self, prog_start: u32, prog_end: u32, progress_modal: &mut Modal, progress_action: &mut Slider) -> Result<(), RootkeyResult> {
let gateware_dest = self.staging.as_slice::<u8>();
let gateware_src = self.gateware.as_slice::<u8>();
fn make_gateware_backup(&self, prog_start: u32, prog_end: u32, progress_modal: &mut Modal, progress_action: &mut Slider) -> Result<(), RootkeyResult> {
let gateware_dest = self.staging();
let mut gateware_dest_base = self.staging_base();
let gateware_src = self.gateware();
log::trace!("src: {:x?}", &gateware_src[0..32]);
log::trace!("dst: {:x?}", &gateware_dest[0..32]);
let mut last_prog_update = 0;
const PATCH_CHUNK: usize = 65536; // this controls the granularity of the erase operation
let mut dest_patch_addr = xous::SOC_STAGING_GW_LOC;
let mut prog_ctr = 0;
for (dst, src) in
gateware_dest.chunks(PATCH_CHUNK).into_iter()
.zip(gateware_src.chunks(PATCH_CHUNK)) {
log::debug!("writing {} backup bytes to address 0x{:08x}", src.len(), dest_patch_addr);
self.spinor.patch(dst, dest_patch_addr, src, 0)
log::debug!("writing {} backup bytes to offset 0x{:08x}", src.len(), prog_ctr);
self.spinor.patch(dst, gateware_dest_base, src, 0)
.map_err(|_| RootkeyResult::FlashError)?;
dest_patch_addr += PATCH_CHUNK as u32;
gateware_dest_base += PATCH_CHUNK as u32;
let progress = ((prog_end - prog_start) * (dest_patch_addr - xous::SOC_STAGING_GW_LOC)) / xous::SOC_STAGING_GW_LEN;
prog_ctr += PATCH_CHUNK as u32;
let progress = ((prog_end - prog_start) * prog_ctr) / xous::SOC_STAGING_GW_LEN;
if progress != last_prog_update {
last_prog_update = progress;
update_progress(progress + prog_start, progress_modal, progress_action);
@ -912,7 +1327,7 @@ impl RootKeys {
log::info!("{}", debugstr);
}
pub fn sign_loader(&mut self, signing_key: &Keypair) -> (Signature, u32) {
pub fn sign_loader(&self, signing_key: &Keypair) -> (Signature, u32) {
let loader_len =
xous::LOADER_CODE_LEN
- SIGBLOCK_SIZE
@ -921,13 +1336,13 @@ impl RootKeys {
// this is a huge hash, so, get a hardware hasher, even if it means waiting for it
let mut hasher = engine_sha512::Sha512::new(Some(engine_sha512::FallbackStrategy::WaitForHardware));
let loader_region = self.loader_code.as_slice::<u8>();
let loader_region = self.loader_code();
// the loader data starts one page in; the first page is reserved for the signature itself
hasher.update(&loader_region[SIGBLOCK_SIZE as usize..]);
// now get the font plane data
self.gfx.bulk_read_restart(); // reset the bulk read pointers on the gfx side
let mut bulkread = BulkRead::default();
let bulkread = BulkRead::default();
let mut buf = xous_ipc::Buffer::into_buf(bulkread).expect("couldn't transform bulkread into aligned buffer");
// this form of loop was chosen to avoid the multiple re-initializations and copies that would be entailed
// in our usual idiom for pasing buffers around. instead, we create a single buffer, and re-use it for
@ -957,9 +1372,9 @@ impl RootKeys {
}
}
pub fn sign_kernel(&mut self, signing_key: &Keypair) -> (Signature, u32) {
pub fn sign_kernel(&self, signing_key: &Keypair) -> (Signature, u32) {
let mut hasher = engine_sha512::Sha512::new(Some(engine_sha512::FallbackStrategy::WaitForHardware));
let kernel_region = self.kernel.as_slice::<u8>();
let kernel_region = self.kernel();
// for the kernel length, we can't know/trust the given length in the signature field, so we sign the entire
// length of the region. This will increase the time it takes to verify; however, at the current trend, we'll probably
// use most of the available space for the kernel, so by the time we're done maybe only 10-20% of the space is empty.

View file

@ -407,7 +407,7 @@ pub struct PatchFrame {{
/// returns a tuple of the value and its inverse; this is done to reduce the timing
/// sidechannel. The inverse value needs to be consumed to prevent the compiler
/// from optimizing out that path.
pub fn patch_frame(frame: u32, offset: u32, rom: &[u32; 256]) -> (Option<u32>, Option<u32>) {{\n""".format(patchlen))
pub fn patch_frame(frame: u32, offset: u32, rom: &[u32]) -> Option<(u32, u32)> {{\n""".format(patchlen))
for frame_rec in patchdata_sorted:
frame = frame_rec[1]
@ -448,13 +448,13 @@ pub fn patch_frame(frame: u32, offset: u32, rom: &[u32; 256]) -> (Option<u32>, O
data_inv |= 1 << bit;
}
}
return (Some(data), Some(data_inv))
return Some((data, data_inv))
}
}
}
}
return (None, None)
return None
}
""")
@ -501,10 +501,10 @@ mod tests {
bitvalue = (keyrom[coord[0]] & (1 << coord[1]))
if bitvalue != 0:
wordvalue |= (1 << bit)
f.write(' assert_eq!(crate::patch_frame({}'.format(frame_rec[0]) + ', ' + '{}'.format(word) + ', ROM), (Some(' + '0x{:08x}'.format(wordvalue) + '), Some(!0x{:08x}'.format(wordvalue) + ')));\n')
f.write(' assert_eq!(crate::patch_frame({}'.format(frame_rec[0]) + ', ' + '{}'.format(word) + ', &ROM), (Some(' + '0x{:08x}'.format(wordvalue) + '), Some(!0x{:08x}'.format(wordvalue) + ')));\n')
f.write(' // also test the null case, frame 0 should typically have no mappings.\n')
f.write(' assert_eq!(crate::patch_frame(0x0, 0, ROM), (None, None) );\n')
f.write(' assert_eq!(crate::patch_frame(0x0, 0, &ROM), (None, None) );\n')
f.write("""
}
}

1034
services/root-keys/src/key2bits/patch.rs Normal file → Executable file

File diff suppressed because it is too large Load diff

View file

@ -5,7 +5,6 @@ pub mod api;
use api::*;
pub mod key2bits;
use key2bits::*;
use xous::{CID, send_message, Message};
use num_traits::*;
@ -106,13 +105,13 @@ impl RootKeys {
pub fn self_sign(&mut self, which: ImageType) -> Result<(), xous::Error> {
unimplemented!();
}
/*
pub fn test_ux(&mut self, arg: usize) {
send_message(self.conn,
Message::new_scalar(Opcode::TestUx.to_usize().unwrap(),
arg, 0, 0, 0)
).expect("couldn't send test message");
}*/
}
}
use core::sync::atomic::{AtomicU32, Ordering};

View file

@ -3,7 +3,7 @@
mod api;
use api::*;
use xous::{CID, msg_scalar_unpack, send_message, Message, msg_blocking_scalar_unpack};
use xous::{msg_scalar_unpack, send_message, msg_blocking_scalar_unpack};
use xous_ipc::{String, Buffer};
use num_traits::*;
@ -188,7 +188,7 @@ fn xmain() -> ! {
xous::yield_slice(); // give some time to the GAM to render
let success = keys.test(&mut rootkeys_modal, &mut progress_action);
let _success = keys.test(&mut rootkeys_modal, &mut progress_action);
} else {
// overall flow:
// - setup the init
@ -217,6 +217,9 @@ fn xmain() -> ! {
Some(ActionType::Notification(dismiss_modal_action)),
Some(t!("rootkeys.setup", xous::LANG)), false,
None, true, None);
////// insert the "are you sure" message at this point in the flow -- don't call setup_key_init() until we're confirmed!
// setup_key_init() prepares the salt and other items necessary to receive a password safely
keys.setup_key_init();
// request the boot password first
@ -280,45 +283,74 @@ fn xmain() -> ! {
xous::yield_slice(); // give some time to the GAM to render
// this routine will update the rootkeys_modal with the current Ux state
let success = keys.do_key_init(&mut rootkeys_modal, &mut progress_action);
let result = keys.do_key_init(&mut rootkeys_modal, &mut progress_action);
// the stop emoji, when sent to the slider action bar in progress mode, will cause it to close and relinquish focus
rootkeys_modal.key_event(['🛑', '\u{0000}', '\u{0000}', '\u{0000}']);
// at this point, we may want to pop up a modal indicating we are going to reboot?
// we also need to include a command that does the reboot.
if success {
dismiss_modal_action.set_action_opcode(Opcode::UxGutter.to_u32().unwrap());
rootkeys_modal.modify(
Some(ActionType::Notification(dismiss_modal_action)),
Some(t!("rootkeys.init.finished", xous::LANG)), false,
None, false, None);
rootkeys_modal.activate();
xous::yield_slice();
match result {
Ok(_) => {
dismiss_modal_action.set_action_opcode(Opcode::UxGutter.to_u32().unwrap());
rootkeys_modal.modify(
Some(ActionType::Notification(dismiss_modal_action)),
Some(t!("rootkeys.init.finished", xous::LANG)), false,
None, false, None);
rootkeys_modal.activate();
xous::yield_slice();
// TODO: insert the reboot code here
} else {
dismiss_modal_action.set_action_opcode(Opcode::UxGutter.to_u32().unwrap());
rootkeys_modal.modify(
Some(ActionType::Notification(dismiss_modal_action)),
Some(t!("rootkeys.init.failure", xous::LANG)), false,
None, false, None);
rootkeys_modal.activate();
xous::yield_slice();
// TODO: insert the reboot code here
}
Err(RootkeyResult::AlignmentError) => {
dismiss_modal_action.set_action_opcode(Opcode::UxGutter.to_u32().unwrap());
rootkeys_modal.modify(
Some(ActionType::Notification(dismiss_modal_action)),
Some(t!("rootkeys.init.fail_alignment", xous::LANG)), false,
None, false, None);
rootkeys_modal.activate();
xous::yield_slice();
}
Err(RootkeyResult::KeyError) => {
dismiss_modal_action.set_action_opcode(Opcode::UxGutter.to_u32().unwrap());
rootkeys_modal.modify(
Some(ActionType::Notification(dismiss_modal_action)),
Some(t!("rootkeys.init.fail_key", xous::LANG)), false,
None, false, None);
rootkeys_modal.activate();
xous::yield_slice();
}
Err(RootkeyResult::IntegrityError) => {
dismiss_modal_action.set_action_opcode(Opcode::UxGutter.to_u32().unwrap());
rootkeys_modal.modify(
Some(ActionType::Notification(dismiss_modal_action)),
Some(t!("rootkeys.init.fail_verify", xous::LANG)), false,
None, false, None);
rootkeys_modal.activate();
xous::yield_slice();
}
Err(RootkeyResult::FlashError) => {
dismiss_modal_action.set_action_opcode(Opcode::UxGutter.to_u32().unwrap());
rootkeys_modal.modify(
Some(ActionType::Notification(dismiss_modal_action)),
Some(t!("rootkeys.init.fail_burn", xous::LANG)), false,
None, false, None);
rootkeys_modal.activate();
xous::yield_slice();
}
}
// clear all the state, re-enable suspend/resume
keys.finish_key_init();
}
}
} else {
log::error!("invalid UX state -- someone called init password return, but no password type was set!");
}
},
/*
Some(Opcode::TestUx) => msg_scalar_unpack!(msg, arg, _, _, _, {
log::debug!("activating password modal");
keys.set_ux_password_type(PasswordType::Boot);
rootkeys_modal.activate();
//policy_menu.activate();
}),*/
keys.printkeys();
}),
Some(Opcode::UxGetPolicy) => {
policy_menu.activate();
}

View file

@ -50,11 +50,11 @@ impl<'a> ShellCmdApi<'a> for Keys {
if let Some(sub_cmd) = tokens.next() {
match sub_cmd {
/*"ux" => {
"ux" => {
self.rootkeys.test_ux(0);
//debug_here::debug_here!();
write!(ret, "show UX").unwrap();
}*/
}
"usblock" => {
env.llio.debug_usb(Some(true)).unwrap();
write!(ret, "USB debug port locked out; one word at 0x80000000 is disclosable via USB.").unwrap();

View file

@ -68,7 +68,7 @@ impl Spinor {
}
#[cfg(not(test))]
fn send_write_region(&mut self, wr: &WriteRegion) -> Result<(), SpinorError> {
fn send_write_region(&self, wr: &WriteRegion) -> Result<(), SpinorError> {
let mut buf = Buffer::into_buf(*wr).or(Err(SpinorError::IpcError))?;
buf.lend_mut(self.conn, Opcode::WriteRegion.to_u32().unwrap()).or(Err(SpinorError::IpcError))?;
@ -88,7 +88,7 @@ impl Spinor {
}
#[cfg(test)]
fn send_write_region(&mut self, wr: &WriteRegion) -> Result<(), SpinorError> {
fn send_write_region(&self, wr: &WriteRegion) -> Result<(), SpinorError> {
let mut i = 0;
if !wr.clean_patch {
assert!((wr.start & 0xFFF) == 0, "erasing is required, but start address is not erase-sector aligned");
@ -109,7 +109,7 @@ impl Spinor {
/// Aside from that, it's the wild west! Think of this as `dd` into a raw disk device node, and not a filesystem-abstracted `write`
/// `region` is a slice that points to the target region that we wish to patch -- ostensibly we should have access to it, so this should
/// just be the MemoryRange turned into a slice.
/// `region_base` is the base address of `region`, given as an offset from base of FLASH (that is, physical address minus 0x2000_0000)
/// `region_base` is the physical base address of `region`, given as an offset from base of FLASH (that is, physical address minus 0x2000_0000)
/// this *must* be aligned to an erase sector.
/// `patch_data` is a slice that contains exactly the data we want to have patched into FLASH. If you're lazy and you just send a large
/// amount of unchanged data with a couple small changes scattered about, this will not be "smart" about it and do a diff and
@ -122,7 +122,7 @@ impl Spinor {
/// Notes:
/// - the server will entirely skip writing over 256-byte pages that are blank. So, if the goal is to erase a region,
/// call patch with data of all 0xFF - this will effectively only do an erase, but no subsequent writes.
pub fn patch(&mut self, region: &[u8], region_base: u32, patch_data: &[u8], patch_index: u32) -> Result<(), SpinorError> {
pub fn patch(&self, region: &[u8], region_base: u32, patch_data: &[u8], patch_index: u32) -> Result<(), SpinorError> {
let align_mask = self.erase_alignment() - 1;
if (region_base & align_mask) != 0 {
return Err(SpinorError::AlignmentError);