1 1
Ravikumar

H3-Soc boot rom security & E-Fuse

Recommended Posts

Hi,

 

I bought nanopi_neo boards (for my hobby projects). I am learning about security.

I am able to dump e-Fuse area at uboot stage. But i can't modify it (i want to write my own key). I don't have any memory map information of e-fuse.

 

In present boards, bootROM is not verifying the uboot signature(RSA sign:-)). 

1) How to enable signature verification in bootROM?

2) Is there any code or information regarding BootROM security and e-Fuse area mapping?

3) Is there any support of TEE (Trusted execution environment)?

 

 

Share this post


Link to post
Share on other sites

You can find some info here: https://linux-sunxi.org/BROM

and here: https://linux-sunxi.org/EGON#eGON.BRM

and disassembled BROM code here: https://github.com/hno/Allwinner-Info/tree/master/BROM

 

I'm pretty sure BROM can only verify checksums and you can't make trusted boot with it.

Thanks for reply,

With present configuration, it just verifying checksum. But there are some unknow bits in efuse to enable security of the chip.

 

Please check following code

 

void sid_set_security_mode(void)
{
    uint reg_val;
 
    reg_val  = sid_read_key(EFUSE_LCJS);
    reg_val |= (0x01 << 11); //ʹÄÜsecurebit
    sid_program_key(EFUSE_LCJS, reg_val);
    reg_val = (sid_read_key(EFUSE_LCJS) >> 11) & 1;
 
    return;
}
 

I have written security (11-bit), now my board is not booting. I think BootROM trying to verify signature.

 

One more thing, H3 is not a simple soc. it has ARM trust zone and it can run TEE(both linux & secure os at a time). BootROM security must for TEE.

Share this post


Link to post
Share on other sites

Well, there is no documentation for BROM and probably there won't be any in the future from Allwinner side.

AFAIK the only way to go forward is to dump and disassemble BROM from H3, and I'm not sure if anyone here (on this forum) has more info on this undocumented stuff.

Share this post


Link to post
Share on other sites

Well, there is no documentation for BROM and probably there won't be any in the future from Allwinner side.

AFAIK the only way to go forward is to dump and disassemble BROM from H3, and I'm not sure if anyone here (on this forum) has more info on this undocumented stuff.

Please check the following code.

                      https://github.com/BPI-SINOVOIP/BPI-M3-bsp

there are some files in u-boot folder

                                       sunxi_efuse.c : efuse map and programing sequencing

                                       usb_burn.c : __sunxi_burn_key for burning efuse area

 

do you know this code? He is burning e-fuse area via usb device.

If you have any information this code. Please share with me.

Share this post


Link to post
Share on other sites

found some infos:

https://github.com/hno/Allwinner-Info/blob/master/BROM/ffff0000.s#L1

 

and looks like allwinner put h3 secure brom source code online:

https://github.com/Allwinner-Homlet/H3-BSP4.4-bootloader/tree/master/uboot_2014_sunxi_spl/sunxi_spl

there many printf -> which use sunxi_serial_putc

however i didn't find the function definition, would be great to get error message why its not booting the toc0

 

i set secure bit and wrote rotpk but it does not boot my toc0 image or any other image anymore only fel mode is working now,

maybe someone has an idea what it could be wrong:

https://pastebin.com/wHWqzPJ7

Share this post


Link to post
Share on other sites

still not yet, only some infos and bricks more...

 

burnend one board without rotpk, only the secure bit flag, does now boot only the toc header images (:

After that i tried jemk script to generate the sha rotpk checksum and wrote into a new board with secure bit,  however this does not boot my sigend toc .... ):

 

Found out there is a private toc0 header with a debug flag, maybe if its possible to set this flag it would be able to get some debug output and infos why the toc does not boot.

Compared source h3 sbrom src with the sha generation from jemks script  and it looks at first view all correct.

 

did you found something out or got it working?

 

Share this post


Link to post
Share on other sites
On 3/4/2019 at 10:22 AM, xeniter said:

still not yet, only some infos and bricks more...

 

burnend one board without rotpk, only the secure bit flag, does now boot only the toc header images (:

After that i tried jemk script to generate the sha rotpk checksum and wrote into a new board with secure bit,  however this does not boot my sigend toc .... ):

 

Found out there is a private toc0 header with a debug flag, maybe if its possible to set this flag it would be able to get some debug output and infos why the toc does not boot.

Compared source h3 sbrom src with the sha generation from jemks script  and it looks at first view all correct.

 

did you found something out or got it working?

 

Hi, unfortunately no, I'm still looking at sbrom source.

I'm even having problems compiling the fuse burner (it gives me linking error in your implementation of printf). Could you tell me how did you manage to compile it?

By the way yes, toc0 header has a debug flag to enable debug prints, but as far as I can see from a sbrom dump they've been removed in production.

What about trying to debug sbrom code by making a fel-bootable image containing part of that code?

Share this post


Link to post
Share on other sites

hi,

did only copy paste the printf somewhere so no warranties.

copied the makefile also somewhere together to compile bare metal, also without warranties

 

https://pastebin.com/x9RftzVm is the makefile (make main.elf)

original is from https://github.com/linux-sunxi/sunxi-tools/blob/master/uart0-helloworld-sdboot.c

had often issues that programmed died, didn't find out why yet so don't trust it

 

the sram is very limited because of the FEL mode see http://linux-sunxi.org/FEL/USBBoot

what helped is to load the uboot spl to init ram, after that i copied my program to the ddr ram.

./sunxi-fel spl ./sunxi-spl.bin
./sunxi-fel write 0x40000000 ./main.elf
./sunxi-fel exe 0x40000000

make sure you adjust linker script with correct adress

-> main.lds     . = 0x40000000;    => set program to start of ddr ram

 

 

found out, or it looks like the ruby tocgen is missing the

#define ITEM_NAME_SBROMSW_KEY    0x010303

 

pack_tools/toc_tools/key_ladder/create_key_ladder.c:    key_item_bin.KEY0_PK_e_len = (key0_e_len+1)>>1;

typedef struct SBROM_TOC0_KEY_ITEM_info {

    unsigned int    vendor_id;
    unsigned int    KEY0_PK_mod_len;
    unsigned int    KEY0_PK_e_len;
    unsigned int    KEY1_PK_mod_len;
    unsigned int    KEY1_PK_e_len;
    unsigned int    sign_len;
    unsigned char    KEY0_PK[PK_MAX_LEN_BYTE];
    unsigned char    KEY1_PK[PK_MAX_LEN_BYTE];
    unsigned char    reserve[32];
    unsigned char    sign[256];
} SBROM_TOC0_KEY_ITEM_info_t;

 

assume h3 boot code reads length from it, that could be a possible reason why its not booting the toc.

haven't tried to add it yet

 

will continue to test it when i have time for it left again...

 

 

Share this post


Link to post
Share on other sites

Hi @xeniter,

were you able to verify the secure boot on H3? I have some spare boards i am willing try on.  Jmks script generates the files, the rotpk-hash is then also programmed but like yours, the nanopi doesnt boot. When setting all the rotpk-hash to all 0xff, the board boots.

 

any help is highly appreciated 

 

wbr

 

Share this post


Link to post
Share on other sites
(edited)

No results yet...

 

Found maybe the original tool to create toc0, always looked over it.

https://github.com/friendlyarm/h3_lichee/tree/75b584e2502450b1e8d2f98ac16fb2410cf8c30a/tools/pack/pctools/linux/openssl

looks like with it it could be possible to create a valid toc0 which boots with key (assume jemk scripts are based on it)

question is now how to use it, haven't tried it yet

 

edit:

generating keys:

/h3_lichee/tools/pack/pctools/linux/openssl/dragonsecboot -toc0 dragon_toc.cfg ../../../common/keys/

generate toc0:

.

/create_toc0 dragon_toc.cfg /h3_lichee/tools/pack/common/keys
dd if=./toc0.fex of=/dev/sd? bs=1024 seek=8

 

> did only boot on my board with rotpk fuses burned with all zeros ):

maybe you have more luck (cause maybe i burned fuses in wrong order... or something else...)

 

used this to generate Trustkey.bin to be able to use my old generated key:

openssl rsa -in rotprivk_rsa.pem -text > /robart/mdipolt/2del/SECBOOT/h3_lichee/tools/pack/common/keys/Trustkey.bin

 

sboot.bin must be raw bin file (no spl and no elf file!)

you can verify your sboot.bin with executing it via fel mode:
 

./sunxi-fel version
./sunxi-fel -p write 0x2000 sboot.bin
./sunxi-fel exe 0x2000

 

create_toc0 created the ".\\x509_rotpk.bin" which had the same rotpk checksum as jemk script, so i assume its correct.

question is how had it to be written into the fuses

 

xxd -i .\\x509_rotpk.bin
unsigned char __x509_rotpk_bin[] = {
  0xf6, 0xab, 0x5e, 0x33, 0x80, 0xd9, 0xdd, 0xa8, 0x82, 0x86, 0x85, 0x5f,
  0x22, 0xdc, 0x9d, 0xc0, 0xf9, 0xa4, 0x2c, 0xbf, 0xec, 0x05, 0xd0, 0xcd,
  0xcd, 0xa4, 0x9b, 0xf4, 0xb4, 0xba, 0xf8, 0x94
};
unsigned int __x509_rotpk_bin_len = 32;

 

i burned it like that:


 

// allwinner H3 == sun8iw7p1
#define SID_PRKEY_NEU	(SUNXI_SID_BASE_NEU + 0x50)
#define EFUSE_ROTPK (0x64)

static void sid_program_key(unsigned int key_index, unsigned int key_value)
{
    unsigned int reg_val;

    writel(key_value, SID_PRKEY_NEU);

    reg_val = readl(SID_PRCTL_NEU);
    reg_val &= ~((0x1ff<<16)|0x3);
    reg_val |= key_index<<16;
    writel(reg_val, SID_PRCTL_NEU);

    reg_val &= ~((0xff<<8)|0x3);
    reg_val |= (SID_OP_LOCK<<8) | 0x1;
    writel(reg_val, SID_PRCTL_NEU);

    while(readl(SID_PRCTL_NEU)&0x1){};

    reg_val &= ~((0x1ff<<16)|(0xff<<8)|0x3);
    writel(reg_val, SID_PRCTL_NEU);

    return;
}

 for(int i = 0; i < 8; i++) {    
        printf("%08x:", rotpk[i]);       
        sid_program_key(EFUSE_ROTPK+4*i, rotpk[i]);
    } 

 

 

 

 

 

 

Edited by xeniter
new tests

Share this post


Link to post
Share on other sites

yes finally it worked (with jemp script, maybe with tocgen also not tested yet...)

you have to write the keys only little endian instead big endian

 

 

 

Share this post


Link to post
Share on other sites
On 5/24/2019 at 10:48 AM, xeniter said:

yes finally it worked (with jemp script, maybe with tocgen also not tested yet...)

you have to write the keys only little endian instead big endian

 

 

 

Hi Xeniter,

Still haven't succeded into booting a TOC0 spl image. 

- Wrote the generated ROTPK as little endian 

 

SHA256 = 18 D8 E4 D5 A2 4D 8B F2 AA 00 61 98 9B 92 15 E7 9B 99 0A 82 F9 21 A6 5B 0F 56 0D A6 D2 05 E8 CE

 

wrote these values in the Key-section of the efuse(0x64...) as little endian : D5 E4 D8 18 .....CE E8 05 D2

Burned 0xF4(LCJS) -> 0x800 (bit 11->'1' to enable secure boot)

 

Used jmek's Ruby script and used the spl which i compiled from a FriendlyArm's Uboot repository(19KB).

 

After jmek's script, a restuling TOC file generated. 

The file boots ok if the keys are burned either as 0's or 1's and secure bit-11 in the 0xF4 is set to '1', but when the nanopi neo board is burned with the exact sha256 , it doesn't boot.

 

Can you please describe step by step what you did in order to get a correct spl and how you programmed the exact sha256 of a .pem file in the Key-efuse section.

 

Thank you

 

wbr

 

Spitfire

Share this post


Link to post
Share on other sites

hi can you post or pm me the private key? assume hash is wrong, simple sha256 hash of pem file is not correct..

 

you can use tocgen to generate it for you, or generate it yourself liked described in the sunxi wiki

ROTPK_HASH = SHA256([Byte 0-255] = RSA modulus || [Byte 256-x] = RSA public exponent || [Byte x-511] filled with 0x91)

means SHA256 from [256 bytes modules + 3 bytes public key exponent ( normally 65537 means 0x010001) + 253*0x91 fill bytes]

 

if you used exactly this key, please try to read the hash back and post me the result + source of reading the rotpk fuse out

 

Share this post


Link to post
Share on other sites

Hi @xeniter

I used tocgen from the lichee repository. So far i was able to generate ,/x509_rotpk.bin file which holds the hash-value to be programmed.

 

the resulting toc0.fex boots ok when the rotpk-hash is all '0's and '1's. (or all keys are the same) with secure-bit burned.

 

 

My read_register routine:

def read_register(register_addr):
    sid_ctrl_data = (0xAC<<8)
    sid_ctrl_data = sid_ctrl_data+(register_addr<<16)
    sid_ctrl_data = sid_ctrl_data+0x02
    #print("SID ctrl content ",hex(sid_ctrl_data))
    writel(sid_base_addr+0x40,sid_ctrl_data)
    while((readl(sid_base_addr+0x40)&0x02)==0x02):
        print("finishing read ..")
        time.sleep(1)
    read_val= readl(sid_base_addr+0x40)
    #print("read val:",hex(read_val))
    reg_val = readl(sid_base_addr+0x60)
    return reg_val

 

programmed HASH in the rotpk section:

('reg ', '0x64', ':', '0xe9e6181a')
('reg ', '0x68', ':', '0x5fb19a8f')
('reg ', '0x6c', ':', '0xf91d6e62')
('reg ', '0x70', ':', '0x652b9fd8')
('reg ', '0x74', ':', '0x3573e89e')
('reg ', '0x78', ':', '0x6f9c3d21')
('reg ', '0x7c', ':', '0xa8f92947')
('reg ', '0x80', ':', '0xf5326ac5')
('reg ', '0x84', ':', '0x0')
('reg ', '0x88', ':', '0x0')
('reg ', '0x8c', ':', '0x0')
('reg ', '0x90', ':', '0x0')
('reg ', '0x94', ':', '0x0')
('reg ', '0x98', ':', '0x0')
('reg ', '0x9c', ':', '0x0')
('reg ', '0xa0', ':', '0x0')
('reg ', '0xa4', ':', '0x0')
('reg ', '0xa8', ':', '0x0')
('reg ', '0xac', ':', '0x0')
('reg ', '0xb0', ':', '0x0')
('reg ', '0xb4', ':', '0x0')
('reg ', '0xb8', ':', '0x0')
('reg ', '0xbc', ':', '0x0')
('reg ', '0xc0', ':', '0x0')
('reg ', '0xc4', ':', '0x0')
('reg ', '0xc8', ':', '0x0')
('reg ', '0xcc', ':', '0x0')
('reg ', '0xd0', ':', '0x0')
('reg ', '0xd4', ':', '0x0')
('reg ', '0xd8', ':', '0x0')
('reg ', '0xdc', ':', '0x0')
('reg ', '0xe0', ':', '0x0')
('reg ', '0xe4', ':', '0x0')
('reg ', '0xe8', ':', '0x0')
('reg ', '0xec', ':', '0x0')
('reg ', '0xf0', ':', '0x0')
('reg ', '0xf4', ':', '0x800')
('reg ', '0xf8', ':', '0x0')
('reg ', '0xfc', ':', '0x0')

 

 

my x509_rotpk_:

unsigned char x509_rotpk_bin[] = {
  0x1a, 0x18, 0xe6, 0xe9, 0x8f, 0x9a, 0xb1, 0x5f, 0x62, 0x6e, 0x1d, 0xf9,
  0xd8, 0x9f, 0x2b, 0x65, 0x9e, 0xe8, 0x73, 0x35, 0x21, 0x3d, 0x9c, 0x6f,
  0x47, 0x29, 0xf9, 0xa8, 0xc5, 0x6a, 0x32, 0xf5
};
unsigned int x509_rotpk_bin_len = 32;

 

 

RSA .pem file:

-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA4T91fvEiHwHeNYKY/mgQ4qWUU7CpzzknpOWAy/MQpwrcAUwy
TCX/nq6FrDPa2yyucpL4Sd3zPACTUURFSzSTYwkglm8fjWX+iCgWlvOYYXlA3Zjl
6nSEhe08mIvbdNHuhEF0yEdHZ1JfHkbwhIU8yq4oqh4sdYshAgLC5WmOoSBoVQOz
7uNms1wHo3Hy2hT9TQ5ed0ttKoPVgH5CgyA19yW+TKVjvpK8vqw1KuHnZILxH9V7
Id/ElSuNPgE8JIdghl9k/cA5HQ4dglWu2pVyKZfIC3VGB1+M5uJCQmatIU9dmoHL
sPaWi79Sn/3qhuxu47en96tShDZL9gasy4qoXwIDAQABAoIBAGeBBJnPblF3R0ep
emo1IcU0NwN6A53QcrIoL9YIHFfV+qCyBc7OCzc8lPo7Xc8nKgZGGMfAsLuavBc0
2u6i+zMgB5R4/bO48YxZd3/n8dagpDjvwH7LCfaMvDKQ2chFi2fEuEgr0NjelgzQ
pkcO/o9YFiGN+foNc5577FkE92B8KgRCsXrKHMx8UZLCmM1Fw3LIsTKWQCm+/7SL
2gb+D3GDwuCnMRrKxQ7J6oYVeMZ/dqxkHhfZdZXy6ofmdmxvabJAism1xXBPJaBl
OD1HX+UAdK2bkIEQDWzVhI+sm2K/0N6MkM3xHxf1gnE0H0Icm8hy6FeZuYm65erc
RlIXsXECgYEA+F6e9Wmh2c2SL7mjxYU1cFj7R3OXE6kR7ln3I/QN7fzH2vmcysB/
3+WhHiWA49rGEMQUjHb9AJ+EYcjyz9PXSLWEWd2rd/78i3SFZvmdZIpNsFJVbhao
hELV/6541ehNymr0XmfU9wCnHY3JUq03Yahrlmabt0h2vRGw3vyVJtcCgYEA6Cr9
eInMhisempaXEgloRT61vkxddQXIfwdZ0GMn4uhgnzRPsQHZXWq4iVj5sD1OOID/
R/oF52MhPrItQKf97unAlrsfFwrVwFX+p8wGwg5OY2Vw44ElfQItWaFXgSZLVtPM
2RRO7pDLHn7dnjuEmSuiBX3DgarzixGTE2ajQbkCgYAFi18zDUueqBcmV5ePVjzu
KB5b5vmtZ63Ny1ZYCB+ze1weyEm2wPtZzS9+k8m/zGd1glsPE6zsMaNr52d8Ojdp
GRw+QVONlzSeDFjaBqJ71xaK5BuiHIFginlqfsOVytzJsv+Hh/vaE7qnTz36SYGd
/XuBXQMG4Wg9KkLvh2Xw+wKBgQCBlEz4U+DFGZfxLA+RT5LU4xVI6xJWWC35SD8G
ofEHIi+ba/T2lFOfYgsxDWn+xZi8zLKul4toA9nwRj4fkiOWjvygpDvL/o4i1VxW
hvdWo+l4bIu/Trt/tBFfrz9Jo/f0tC3nEwCjAkl78c77m7h8TPAXJIRUAPgBLIPs
FiMUcQKBgEjAqVqrYpxf/LjVDmE97lzKwR2Yb+BIuzH+4e7QlQEtg9IqVK53+Re1
p4nb46r643RJEkoDLwJqvZQoqngCsSkKCd5jAG1cE9mMyaT/shNDwefYMULf7FLr
ScKN2oP6LVdye+2shTMDKfv6fbb2NQ2E3xYThzhUmNvMnkZbj4d8
-----END RSA PRIVATE KEY-----

 

 

I have used the /keys folder which i first used the create_keys script for and the posted key is the Trustkey.pem

 

Still unable to boot in secure-mode, any help is appreciated.

 

wbr

 

spitfire

 

 

Share this post


Link to post
Share on other sites

looks like your rotpk key is okay

 

verified with:

https://pastebin.com/ShSQFe95

rotpk
00000000  1a 18 e6 e9 8f 9a b1 5f 62 6e 1d f9 d8 9f 2b 65  |......._bn....+e|
00000010  9e e8 73 35 21 3d 9c 6f 47 29 f9 a8 c5 6a 32 f5  |..s5!=.oG)...j2.|

 

only used tocgen from lichee when fuses where all zero, did you try it also with jemk egon2toc.rb?

 

here is my bare metal example of writing the key, use it at own risk! and double check you replaced your rotpk (1a=f6.... 94=f5) correctly:

https://pastebin.com/Aw5q6bdU

 

to read keys create new main and call print_stuff and add a smc instruction before it to be able to print your burned roptk key via fel mode

to run it via fel from sdram:
arm-none-eabi-objcopy -O binary main.elf main.bin
./sunxi-fel version
./sunxi-fel -p write 0x2000 main.bin
./sunxi-fel exe 0x2000

 

 

Share this post


Link to post
Share on other sites

@xeniter

finally good news: i was able to boot the SoC in secure mode...

 

using the jmk's egon2toc did the trick. Before i was using the lichee's toc generator, i guess that has some sort of bug.

I used sunxi-fel to burn my keys.

The keys should be of course burned "little-endian"

 

anyways, thanks for your tremendous work and help.

 

wbr

 

 

Share this post


Link to post
Share on other sites

@xeniter now that secure spl is working, i guess, is there any way to disable fel? as securing the spl does not overcome someone to gain access over fel.... and program the rotpk to all '1' and run their own "certified spl"

i guess there might be a SID-bit to burn after which no modification is allowed to the SID...

 

I will keep digging and see if you have info as well.

Share this post


Link to post
Share on other sites

@spitfirenice to hear that it finally worked

strange that the original tocgen does not work, was lucky that i test the ruby script before.

good point with fel mode, would be very interesting if its possible somehow to disable it

Share this post


Link to post
Share on other sites

can we use this secure mode to run encrypted sd card ?

or its only to be sure the os isn't changed by using trust chain

thanks

Share this post


Link to post
Share on other sites

now its only for verification of the spl bootloader, maybe you could write some aes keys in the fuses and use it later for decryption.

the h3 has also a crypto engine didn't look into deeper it yet, maybe someone has some experience with it already

Share this post


Link to post
Share on other sites

I'm also looking for a solution to enable secure boot with encrypted SD card and so having a few questions:

1) Is this method applicable to H5 also or it will work only on H3?

2) Are data stored in eFuses (encryption key) are secured? Can someone with physical access to device read them?

3) This topic is very important for IoT devices that store sensitive data in their memory so it will be very helpful if you guys could provide step-by-step instructions on how to enable secure boot with storing an encryption key in eFuses (for newbies to this platform).

Share this post


Link to post
Share on other sites

1) According to Sunxi toc wiki -> You may need to change the entry point address from 0x0 to 0x10000 if you want to run it on A64/H64/H5 (the default 0x0 value is used for H3)

have never tested secure toc boot on other hardware than H3, assume it will also work on H5

2) Yes, it is possible to read it via fel mode, since till now as far I know nobody found out how to disable it, the better question is -> is it really possible to disable it...

3) stop dreaming and buy a arm core with documentation or at least from a manufacturer where you can get it, otherwise you are on your own

you could try ask allwinner, here some possible answers you may get:

there is no documentation about this...

what is toc0? <- made my day^^

 

possible solution:

Easiest way is maybe to burn the key in the AES fuses, read it from ram via u-boot and pass it as crypt variable to the kernel parameter (https://wiki.archlinux.org/index.php/Dm-crypt/System_configuration)

maybe someone who will use this setup could post the steps, anyhow i wouldn't trust such a step per step without fully understanding each step and its likely you have to adjust anyhow something.

Share this post


Link to post
Share on other sites
Useful links
link description
1 this topic full instruction by itself - extremely useful
2 SID Register Guide description of eFUSE fields; likely created while looking through this code from [11]
3 FEL info description of FEL mode and how to switch in FEL (see also [9])
4 jemk script ruby-script to pack SPL binary into TOC0 format (see also create_toc0 in 6) )
5 newer SPL sources (2014) likely original SPL (aka SBromSW) from Allwinner; based on U-Boot 2014
6 AW openssl tools tools for generating keys and TOC0 from Allwinner SDK
7 uart0-helloworld-sdboot code that works on bare metal Allwinner SoC, also in FEL-mode
8 sunxi tools info tool for working with FEL and other useful stuff
9 more on FEL more info about FEL mode (just useful to read)
10 eFUSE burner working code, that burns rotpk from @xeniter (base on code in [7])
11 original SPL original Allwinner SPL for H3
12 eFUSE structure full description of eFUSE structure (likely [2] is based on this code)
13 Nanopi Neo firmware firmware (and it's source code)
14 Brom sources original Brom sources, dumped from SoC (assembler, not C-sources)


Brom == SBromHW == boot ROM - first loader, burned inside SoC

SPL == SBromSW == Second Program Loader - second loader, verified and loaded by Brom with help of rotpk

U-Boot - third loader, verified and loaded by SPL

rotpk == Root Of Trust Public Key - the most important key, burned into eFUSE (as ROTPK_HASH, counted by this formula), as verification chain starts from it

Semelis == Secure OS - some code, that works in Secure World (likely just Linux)

Normal OS - some code, that works in Normal World (Linux, Android, etc.)

 

verification chain:

  1. power on => starts Brom
  2. Brom looks for SPL on persistent memory (SD-card, eMMC, etc.; for SD-card it looks at offset 8kb); SPL not present => goto FEL
  3. Brom checks for rotpk in eFUSE
    1) rotpk present: verify and load SPL; verification failed => goto FEL
    2) rotpk not present: load SPL
  4. SPL checks for rotpk
    1) rotpk present: goto 5.
    2) rotpk not present: burn rotpk and other keys into eFUSE
  5. SPL checks for secure U-Boot
    1) secure U-Boot not found => likely goto FEL (may be options, depending on SPL logic)
    2) verify secure U-Boot with some keys (depends on SPL logic); verification failed => goto FEL
    3) load secure U-Boot
  6. secure U-Boot verifies and loads Semelis, or goes to FEL, if comething is wrong
  7. SPL checks for normal U-Boot
    1) normal U-Boot not found => likely goto FEL (may be options, depending on SPL logic)
    2) verify normal U-Boot with some keys (depends on SPL logic); verification failed => likely goto FEL (may be options, depending on SPL logic)
    3) load normal U-Boot
  8. normal U-Boot verifies and loads Normal OS or, if comething is wrong, likely goto FEL (may be options, depending on normal U-Boot logic)
  9. two full featured (Normal and Secure) OSes are running and communicating

Full featured TrustZone is: two full featured (kernel space + user space ) Linux , one works inside Normal World, another inside Secure World. Monitor Mode - some code, that clues two worlds. Normal World issues software interrupt (ARM instruction SMC). Normal World kernel implements Monitor Mode - verifies if the switch between worlds is possible, saves some parameters for Secure World handler and issues SMC instruction. Secure World kernel handles software interrupt, issued by SMC instruction, executes some work, issued by Normal World parameters and returns back from SMC software interrupt handler to Normal Wold.

There may be ortions, so Semelis could be something more simple than full featured Linux.

 

to burn eFUSE

1) build sunxi-tools

apt-get install libusb-1.0-0-dev
git clone https://github.com/linux-sunxi/sunxi-tools sunxi_tools_dir
cd ./sunxi_tools_dir
make

2) switch H3 into FEL

just pull SD-card out and turn on

to check:

cd ./sunxi_tools_dir
 
# list shows all connected Allwinner SoC's that are in FEL mode
./sunxi-fel list
USB device 001:009   Allwinner H3      02c00081:04004620:79910124:5c1a080e
 
# sid shows CHIPID from eFUSE (see [2])
./sunxi-fel sid 
02c00081:04004620:79910124:5c1a080e

3) compile and run uart0-helloworld-sdboot

Before continue also would be useful to connect Nanopi Neo UART to PC - there would logs printed in H3 UART0. Also install crosscompiler (used Linaro GCC 4.9-2015.03, prefix arm-angstrom-linux-gnueabi-, for tests).

cd ./sunxi_tools_dir

# compile uart0-helloworld-sdboot; Makefile has instructions to autosearch crosscompiler, but in case
# run: CROSS_COMPILE=arm-angstrom-linux-gnueabi- make uart0-helloworld-sdboot.elf
make uart0-helloworld-sdboot.elf
 
# load binary into SRAM A1 on H3
./sunxi-fel -v -p write 0x2000 ./uart0-helloworld-sdboot.elf

# run code; UART should show:
#
# Hello from Allwinner H3!
# Returning back to FEL.
#
./sunxi-fel -v exec 0x2000

4) generating keys

Keys are generated with by dragonsecboot from [6]. Parameters of this utility are unknown (no --help flag), so look at this post and tools/pack/createkeys in [6].

git clone https://github.com/friendlyarm/h3_lichee.git h3_lichee
cd ./h3_lichee/tools/pack/pctools/linux/openssl

# flag -key found in h3_lichee/tools/pack/createkeys
PATH=".:$PATH" dragonsecboot -key ../../../common/sign_config/dragon_toc.cfg ../../../common/keys

dragonsecboot generates bunch of private keys and name files, as mentioned in file dragon_toc.cfg. For every key also generated .bin file (it is a text file actually) with some mathematical processing. Also one of the keys is mentioned as Trustkey. For this one rotpk.bin is generated - this is our Root Of Trust hash to write to eFUSE.

 

5) build eFUSE burner

Take the working code [10] from @xeniter. Change rotpk_bin on the data from your rotpk.bin from 4). Compile and run it as in 3). That's all - @xeniter already done everything for you:)

 

6) generating TOC0

create_toc0 from [6] (could be found near dragonsecboot) and jemk script [4] do pretty the same, but using jemk script is easier: 

# install Ruby
sudo apt-get install ruby-full
# ruby -v
 
git clone git@gist.github.com:2abcab1359c4bce793679c5854062331.git jemk_mktoc0
 
# generate TOC0
# Trustkey.pem - Root of Trust, from which rootpk. bin was generated in 4),
# sboot.bin - compiled binary SPL, for test simply uart0-helloworld-sdboot could be used
# sboot.toc0 - output file
ruby ./jemk_mktoc0/mktoc0.rb [path_to_BSP]/h3_lichee/tools/pack/common/keys/Trustkey.pem [path_to_SPL]/sboot.bin sboot.toc0
# ruby ./jemk_mktoc0/mktoc0.rb [path_to_BSP]/h3_lichee/tools/pack/common/keys/Trustkey.pem [sunxi_tools_dir]/uart0-helloworld-sdboot.elf sboot.toc0

Just in case, create_toc0 could be used like this

cd [path_to_BSP]/h3_lichee/tools/pack/pctools/linux/openssl

# create_toc0 is controlled by the same config dragon_toc.cfg as dragonsecboot - see section [toc0] in dragon_toc.cfg
# actually the name of binary to pack into TOC0 is also specified there - it's sboot.bin, so we should copy binary here, or
# specify another full path
cp [path_to_SPL]/sboot.bin ./sboot.bin

# run create_toc0 (create_toc0 uses keys, generated by dragonsecboot)
PATH=".:$PATH" create_toc0 ../../../common/sign_config/dragon_toc.cfg ../../../common/keys

7) run board with custom TOC0 and rotpk

Insert SD-card and flask your SPL in TOC0 format there

sudo dd if=[path_to_toc0]/sboot.toc0 of=/dev/sd[?] status=progress bs=1024 seek=8

Now insert SD-card and run board. If you used uart0-helloworld-sdboot.elf as a binary inside TOC0, you should see some output from device UART0.

Share this post


Link to post
Share on other sites
On 6/22/2019 at 1:56 AM, Yevhen said:

I'm also looking for a solution to enable secure boot with encrypted SD card and so having a few questions:

1) Is this method applicable to H5 also or it will work only on H3?

2) Are data stored in eFuses (encryption key) are secured? Can someone with physical access to device read them?

3) This topic is very important for IoT devices that store sensitive data in their memory so it will be very helpful if you guys could provide step-by-step instructions on how to enable secure boot with storing an encryption key in eFuses (for newbies to this platform).

About 2). As @xeniter mentioned before, it is not secure - one can read it via FEL mode due to hack implemented in sunxi-fel utility:

// file fel.c in sunxi-tools

/*
 * Issue a "smc #0" instruction. This brings a SoC booted in "secure boot"
 * state from the default non-secure FEL into secure FEL.
 * This crashes on devices using "non-secure boot", as the BROM does not
 * provide a handler address in MVBAR. So we have a runtime check.
 */
void aw_apply_smc_workaround(feldev_handle *dev)
{
    soc_info_t *soc_info = dev->soc_info;
    uint32_t val;
    uint32_t arm_code[] = {
        htole32(0xe1600070), /* smc #0  */
        htole32(0xe12fff1e), /* bx  lr  */
    };
 
 
    /* Return if the SoC does not need this workaround */
    if (!soc_info->needs_smc_workaround_if_zero_word_at_addr)
        return;
 
    /* This has less overhead than fel_readl_n() and may be good enough */
    aw_fel_read(dev, soc_info->needs_smc_workaround_if_zero_word_at_addr,
                &val, sizeof(val));
 
    /* Return if the workaround is not needed or has been already applied */
    if (val != 0)
        return;
 
    pr_info("Applying SMC workaround... ");
    aw_fel_write(dev, arm_code, soc_info->scratch_addr, sizeof(arm_code));
    aw_fel_execute(dev, soc_info->scratch_addr);
    pr_info(" done.\n");
}

 

But we implemented another hack on this hack - we burned USB)) It's definitely not elegant and not tested well (we don't know for sure, if only USB is burned, but not some other useful parts of the SoC), but finally USB data channels are broken (D+ and D-) but power channels are ok - Nanopi Neo still gets power via USB, but FEL mode is completely unavailable. To do this, we connected USB data channels D+ and D- to 20V power source via capacitor of 0.22uF.

------------------------- D+

20v

-------- 0.22uF -------- D-

Share this post


Link to post
Share on other sites

thanks for the nice summary,

epic fel mode solution( made my day :D) why i didn't think about it, hope you verify in your EOL tests that fel mode is really not working anymore

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
1 1