diff --git a/src/include/securerom/ROM.H b/src/include/securerom/ROM.H new file mode 100644 index 00000000000..315a436d0e5 --- /dev/null +++ b/src/include/securerom/ROM.H @@ -0,0 +1,133 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/include/securerom/ROM.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/**************************************************************************** + * + ****************************************************************************/ +#ifndef ROM_H +#define ROM_H + +/****************************************************************************/ +#ifndef PHYPLIBFUNCTIONS +#include +#endif +#include +#include + +/****************************************************************************/ +#define CONTAINER_VERSION 1 +#define HEADER_VERSION 1 +#define HASH_ALG_SHA512 1 +#define SIG_ALG_ECDSA521 1 + +#define HBI_BASE_SIGNING_KEY 0x80000000 + +#define ROM_MAGIC_NUMBER 0x17082011 + +typedef struct { + uint16_t version; // (1: see versions above) + uint8_t hash_alg; // (1: SHA-512) + uint8_t sig_alg; // (1: SHA-512/ECDSA-521) +}__attribute__((packed)) ROM_version_raw; + +typedef struct { + uint32_t magic_number; // (17082011) + uint16_t version; // (1: see versions above) + uint64_t container_size; // filled by caller + uint64_t target_hrmor; // filled by caller + uint64_t stack_pointer; // filled by caller //bottom of stack -> 128k added by rom code to get real stack pointer + ecc_key_t hw_pkey_a; + ecc_key_t hw_pkey_b; + ecc_key_t hw_pkey_c; + uint64_t prefix; // prefix header place holder + // followed by sw header (if not special prefix) + // followed by optional unprotected payload data +}__attribute__((packed)) ROM_container_raw; + +typedef struct { + ROM_version_raw ver_alg; + uint64_t code_start_offset; + uint64_t reserved; + uint32_t flags; + uint8_t sw_key_count; + uint64_t payload_size; + sha2_hash_t payload_hash; + uint8_t ecid_count; + uint8_t ecid[ECID_SIZE]; // optional ecid place holder ecid_count * ecid_size(128 bits) + // followed by prefix data (sig,keys) key raw +}__attribute__((packed)) ROM_prefix_header_raw; + +#define PREFIX_HEADER_SIZE(_p) (sizeof(ROM_prefix_header_raw)+((_p->ecid_count-1)*ECID_SIZE)) + +typedef struct { + ecc_signature_t hw_sig_a; + ecc_signature_t hw_sig_b; + ecc_signature_t hw_sig_c; + ecc_key_t sw_pkey_p; + ecc_key_t sw_pkey_q; + ecc_key_t sw_pkey_r; +}__attribute__((packed)) ROM_prefix_data_raw; + +typedef struct { + ROM_version_raw ver_alg; + uint64_t code_start_offset; + uint64_t reserved; + uint32_t flags; + uint8_t reserved_0; + uint64_t payload_size; + sha2_hash_t payload_hash; + uint8_t ecid_count; + uint8_t ecid[ECID_SIZE]; // optional ecid place holder ecid_count * ecid_size(128 bits) + // followed by sw sig raw +}__attribute__((packed)) ROM_sw_header_raw; + +#define SW_HEADER_SIZE(_p) (sizeof(ROM_sw_header_raw)+((_p->ecid_count-1)*ECID_SIZE)) + +typedef struct { + ecc_signature_t sw_sig_p; + ecc_signature_t sw_sig_q; + ecc_signature_t sw_sig_r; + // followed by zero's padding to 4K + // followed by protected sw payload_data + // followed by unprotected sw payload_text +}__attribute__((packed)) ROM_sw_sig_raw; + +/****************************************************************************/ +typedef enum { ROM_DONE, ROM_FAILED, PHYP_PARTIAL } ROM_response; + +#ifndef PHYPLIBFUNCTIONS +typedef struct { + sha2_hash_t hw_key_hash; + uint8_t my_ecid[ECID_SIZE]; + uint64_t entry_point; + uint64_t log; +}__attribute__((packed)) ROM_hw_params; + +//extern void ROM_instruction_start (void); +extern void ROM_sreset (void); +extern ROM_response ROM_verify (ROM_container_raw* container, + ROM_hw_params* params); +#endif + +#endif diff --git a/src/include/securerom/ecverify.H b/src/include/securerom/ecverify.H new file mode 100644 index 00000000000..b7c707803b5 --- /dev/null +++ b/src/include/securerom/ecverify.H @@ -0,0 +1,55 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/include/securerom/ecverify.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/*---------------------------------------------------------------------- + * (C) COPYRIGHT INTERNATIONAL BUSINESS MACHINES CORPORATION 2010 + * ALL RIGHTS RESERVED + * IBM Research, Zurich and IBM Crypto Competency Center, Copenhagen + *---------------------------------------------------------------------- + * Author: Tamas Visegrady (tvi@zurich.ibm.com) + *----------------------------------------------------------------------*/ + +#if !defined(__ECVERIFY_H__) +#define __ECVERIFY_H__ + +/** ECDSA verification on fixed curve + */ + +#define EC_HASHBYTES 64 /* SHA-256 */ +#define EC_COORDBYTES 66 /* P-521 */ + +typedef uint8_t ecc_key_t[2*EC_COORDBYTES]; +typedef uint8_t ecc_signature_t[2*EC_COORDBYTES]; + +/** Returns positive if signature verified + * zero if parameters are valid but signature verification fails + * negative if parameters (such as point) are invalid + */ +int ec_verify (const uint8_t *publicpt, /* 2*EC_COORDBYTES */ + const uint8_t *hash, /* EC_HASHBYTES */ + const uint8_t *signature) ; /* 2*EC_COORDBYTES */ + +#define NDEBUG + +#endif /* defined(__ECVERIFY_H__) */ diff --git a/src/include/securerom/hw_utils.H b/src/include/securerom/hw_utils.H new file mode 100644 index 00000000000..324cdfc253b --- /dev/null +++ b/src/include/securerom/hw_utils.H @@ -0,0 +1,430 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/include/securerom/hw_utils.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/**************************************************************************** + * + ****************************************************************************/ +#ifndef HW_UTILS_H +#define HW_UTILS_H + +#include + +#include "sha512.h" +#include "status_codes.h" + +#define ECID_SIZE 16 +#define CACHE_LINE 128 +#define XSCOM_MASK 0x0003fe0000000000ull // bit 14:22 implemented +#define HRMOR_MASK 0x0003fffffe000000ull // 32MB aligned +#define STACK_MASK 0x0003fffffffff000ull // 4KB page aligned //WEH bug fix +#define ENTRY_MASK 0x7ffffffffffffffCull // 4Byte page aligned + +#define HRMOR_IGNORE 0x8000000000000000ull +#define HRMOR_RELATIVE(_a) ((_a)&~HRMOR_IGNORE) +#define ABSOLUTE_ADDR(_a) ((_a)|HRMOR_IGNORE) + + +#define CONTEXT 0 + +#ifdef EMULATE_HW + +extern int FAIL; +extern int GOOD; + +#define HOST_RESET_VECTOR 0x100 + +#define TEST_SYSTEM_MEMORY (64*1024*1024) +#define TRUSTED_MEMORY_BASE (8*1024*1024) // should be 256MB +#define TOTAL_TEST_MEMORY (TEST_SYSTEM_MEMORY+4*1024) +#define MEMORY_MASK 0x7fffffffffffffffull +#define CACHE_MASK 0x7fffffffffffff80ull // 128B cache line aligned + +#define PHYSICAL(_a) ((_a)&MEMORY_MASK) + +#define LOG(_c) Log(CONTEXT|(_c)) +#define CHECK_STOP(_m) Check_Stop(_m) +#define ERROR_STOP(_c,_m) Error_Stop(CONTEXT|(_c), _m) + +typedef struct { + uint64_t GPR[32]; + uint64_t SCRATCH0; + uint64_t SCRATCH1; + uint64_t SCRATCH2; + uint64_t SCRATCH3; + uint64_t HRMOR; + struct { + uint64_t value; + uint64_t mask; + } FSP_BAR; + uint8_t ECID[ECID_SIZE]; + sha2_hash_t PIBMEM_HW_KEY_HASH; + uint8_t* data; // 64M+4K malloc/mmap + uint8_t* memory; // 64M (4K aligned) + int mfd; +} hw_settings; + +extern hw_settings HW; + +#define r1 HW.GPR[1] +#define r2 HW.GPR[2] + +extern void HW_Init (void); +extern void HW_Free (void); + +extern void Log (uint64_t code); +extern void Error (uint64_t code); +extern void Check_Stop (char* msg); +extern void Error_Stop (uint64_t code, char* msg); + +extern void assem_DCBI (uint64_t addr); +extern void assem_DCBZ (uint64_t addr); +extern void assem_DCBST (uint8_t* addr); +extern void assem_ICBI (uint64_t* addr); +extern void assem_SYNC (void); +extern void assem_ISYNC (void); + +extern void mtspr_HRMOR (uint64_t addr); +//extern uint64_t mfspr_HRMOR (void); + +static inline uint64_t mfspr_SCRATCH0(void) { + return HW.SCRATCH0; +} + +static inline void mtspr_SCRATCH0(uint64_t val) { + HW.SCRATCH0 = val; +} + +static inline uint64_t mfspr_SCRATCH1(void) { + return HW.SCRATCH1; +} + +static inline void mtspr_SCRATCH1(uint64_t val) { + HW.SCRATCH1 = val; +} + +static inline void mtspr_SCRATCH2(uint64_t val) { + HW.SCRATCH2 = val; +} + +static inline uint64_t mfspr_SCRATCH2(void) { + return HW.SCRATCH2; +} + +static inline void mtspr_SCRATCH3(uint64_t val) { + HW.SCRATCH3 = val; +} + +static inline uint64_t mfspr_SCRATCH3(void) { + return HW.SCRATCH3; +} + +extern uint64_t getscom_FSP_BAR_value (uint64_t base); +extern uint64_t getscom_FSP_BAR_mask (uint64_t base); + +extern void getscom_HW_ECID (uint64_t base, uint8_t* buf); +extern void getscom_PIBMEM_HW_Key_Hash (uint64_t base, uint8_t* buf); + +extern uint64_t physical_addr (uint64_t addr); +extern uint8_t* Convert_Mem_Addr (uint64_t); +extern uint64_t Convert_Mem_Offset (uint8_t*); + +/****************************************************************************/ +extern uint16_t GET16 (uint16_t data); +extern uint32_t GET32 (uint32_t data); +extern uint64_t GET64 (uint64_t data); + +#else //emulate_hw + +/* SPRs numbers -- the wrong ones: */ +//#define SPRG0 272 /* Software Special Purpose Register 0 */ +//#define SPRG1 273 /* Software Special Purpose Register 1 */ +//#define SPRG2 274 /* Software Special Purpose Register 2 */ +//#define SPRG3 275 /* Software Special Purpose Register 3 */ + +#define SPRC 276 +#define SPRC_SCRATCH0 0x0000000000000040 +#define SPRC_SCRATCH1 0x0000000000000048 +#define SPRC_SCRATCH2 0x0000000000000050 +#define SPRC_SCRATCH3 0x0000000000000058 +#define SPRC_AVP_out 0x00000000000001C8 +#define SPRD 277 + +#define HRMOR 313 + +#define HMER 336 +#define HMER_XSCOM_FAIL 0x0080000000000000 //Bit 8 +#define HMER_XSCOM_DONE 0x0040000000000000 //Bit 9 +#define HMER_XSCOM_RSLT 0x0000070000000000 //Bit 21-23 +#define HMER_XSCOM_RTRY 0x0000010000000000 //RSLT = 001 = retry + +/* SCOM Register addresses */ +#define OTP 0x00018000 +#define OTP_ECID OTP +0x0000 +#define PIBMEM 0x00080000 +#define PIBMEM_HW_KEY_HASH PIBMEM +0x0008 + +#define ALTD_UNTRUSTED_BAR_ADDR_REG 0x02020015 +#define ALTD_UNTRUSTED_BAR_MASK_ADDR_REG 0x02020016 +#define PSIHB_NOTRUST_BAR0 0x02013f40 +#define PSIHB_NOTRUST_BAR0MASK 0x02013f42 +#define PSIHB_NOTRUST_BAR1 0x02013f41 +#define PSIHB_NOTRUST_BAR1MASK 0x02013f43 + +/****************************************************************************/ +static inline void assem_DCBI(uint64_t addr) { + asm volatile(" dcbi 0,%0 " : : "r" (addr) : "memory"); +} +/****************************************************************************/ +static inline void assem_DCBZ(uint64_t addr) { + asm volatile(" dcbz 0,%0 " : : "r" (addr) : "memory"); +} +/****************************************************************************/ +static inline void assem_ICBI(uint64_t* addr) { + asm volatile(" icbi 0,%0 " : : "r" (addr) : "memory"); +} +/****************************************************************************/ +static inline void assem_SYNC(void) { + asm volatile("sync 0":::"memory"); +} +/****************************************************************************/ +static inline void assem_ISYNC(void) { + asm volatile("isync":::"memory"); +} +/****************************************************************************/ + +static inline uint64_t mfspr(int reg) { + unsigned long val; + asm volatile("mfspr %0, %1" : "=r" (val) : "i" (reg)); + return val; +} + +static inline void mtspr(int reg, uint64_t val) { + asm volatile("mtspr %0, %1" : : "i" (reg), "r" (val)); +} + +/****************************************************************************/ +// +//static inline uint64_t mfspr_HRMOR(void) { +// unsigned long val; +// asm volatile("mfspr %0, %1" : "=r" (val) : "i" (HRMOR)); +// return val; +//} + +static inline void mtspr_HRMOR(uint64_t addr) { + asm volatile("mtspr %0, %1" : : "i" (HRMOR), "r" (addr & HRMOR_MASK)); +} + +/****************************************************************************/ +#if !(CONFIG_MAMBO && CONFIG_MAMBO_WITHOUT_SCRATCH) + +static inline uint64_t mfspr_SCRATCH0(void) { + mtspr(SPRC,SPRC_SCRATCH0); + return mfspr(SPRD); +} + +static inline void mtspr_SCRATCH0(uint64_t val) { + mtspr(SPRC,SPRC_SCRATCH0); + mtspr(SPRD,val); +} + +static inline uint64_t mfspr_SCRATCH1(void) { + mtspr(SPRC,SPRC_SCRATCH1); + return mfspr(SPRD); +} + +static inline void mtspr_SCRATCH1(uint64_t val) { + mtspr(SPRC,SPRC_SCRATCH1); + mtspr(SPRD,val); +} + +static inline void mtspr_SCRATCH2(uint64_t val) { + mtspr(SPRC,SPRC_SCRATCH2); + mtspr(SPRD,val); +} + +static inline void mtspr_SCRATCH3(uint64_t val) { + mtspr(SPRC,SPRC_SCRATCH3); + mtspr(SPRD,val); +} + +#else + + #define mfspr_SCRATCH0() ci_read( 0x80C0FFEE00000000ull) + #define mtspr_SCRATCH0(value) ci_write(0x80C0FFEE00000000ull,(value)) + #define mfspr_SCRATCH1() ci_read( 0x80C0FFEE00000008ull) + #define mtspr_SCRATCH1(value) ci_write(0x80C0FFEE00000008ull,(value)) + #define mfspr_SCRATCH2() ci_read( 0x80C0FFEE00000010ull) + #define mtspr_SCRATCH2(value) ci_write(0x80C0FFEE00000010ull,(value)) + #define mfspr_SCRATCH3() ci_read( 0x80C0FFEE00000018ull) + #define mtspr_SCRATCH3(value) ci_write(0x80C0FFEE00000018ull,(value)) + +#endif +/****************************************************************************/ + +void __attribute__((noreturn)) Check_Stop(void); + +/****************************************************************************/ + +#define LOG(_c) mtspr_SCRATCH2(CONTEXT|(_c)) +#define ERROR_STOP(_c,_m) { mtspr_SCRATCH3(ERROR_EVENT|CONTEXT|(_c)); asm volatile("b .Check_Stop"); } + + +/****************************************************************************/ +/* Bit 56, 61, 62, 63 is not used in XSCOM addresss and must be 0 + */ +#define PCB2PBUS(scom_addr) \ + ((((scom_addr) & 0x7FFFFFF0) << 4) | \ + (((scom_addr) & 0x0000000F) << 3)) + + +static inline uint64_t ci_read(const uint64_t reg) { + unsigned long val; + asm volatile( "ldcix %0, 0, %1" + : "=r" (val) // output, %0 + : "r" (reg) // input, %1 + // no impacts + ); + //old prism code: + //asm volatile( "ld %0, 0(%1)\n" + // "eieio" + // : "=r" (val) /* output */ + // : "r" (reg) /* input */ + // ); + return val; +} + + +static inline void ci_write(const uint64_t reg, uint64_t val) { + asm volatile("stdcix %0, 0, %1" + : // no outputs + : "r" (val), "r" (reg) // inputs, %0, %1 + : "memory" // affects memory + ); + //old prism code: + //asm volatile("st %0, 0(%1)\n" + // "eieio" + // : /* output */ + // : "r" (val) , "r" (reg) /* input */ + // : "memory"); +} + +#ifndef CONFIG_MAMBO + + #define getscom(a, b) _getscom((a)+PCB2PBUS(b)) + static inline uint64_t _getscom(uint64_t addr) { + mtspr(HMER,0); + uint64_t value; + uint64_t rslt; + do { + value = ci_read(addr); + do { + rslt = mfspr(HMER)&(HMER_XSCOM_RSLT|HMER_XSCOM_DONE|HMER_XSCOM_FAIL); + } while( (rslt & HMER_XSCOM_DONE)==0 ); + } while(rslt == (HMER_XSCOM_RTRY|HMER_XSCOM_DONE|HMER_XSCOM_FAIL) ); // 001 retry + if(rslt != HMER_XSCOM_DONE){ + ERROR_STOP(XSCOM_ERROR,"XScom read returned unexpected result code"); + } + return value; + } + + #define putscom(xscom_base, scom_addr, value) _putscom(xscom_base + PCB2PBUS(scom_addr),value) + static inline void _putscom(uint64_t addr, uint64_t value) { + mtspr(HMER,0); + uint64_t rslt = -1; + do { + ci_write(addr,value); + do { + rslt = mfspr(HMER)&(HMER_XSCOM_RSLT|HMER_XSCOM_DONE|HMER_XSCOM_FAIL); + } while( (rslt & HMER_XSCOM_DONE)==0 ); + } while(rslt == (HMER_XSCOM_RTRY|HMER_XSCOM_DONE|HMER_XSCOM_FAIL) ); // 001 retry + if(rslt != HMER_XSCOM_DONE){ + ERROR_STOP(XSCOM_ERROR,"XScom write returned unexpected result code"); + } + } + +#else + + #define getscom(xscom_base, scom_addr) ci_read(xscom_base+scom_addr*8) + #define putscom(xscom_base, scom_addr, value) ci_write(xscom_base+scom_addr*8,value) + +#endif + + + +static inline uint64_t popcountll(uint64_t input) { + unsigned long result; + asm volatile("popcntd %0, %1" : "=r" (result) : "r" (input)); + return result; +} + +/****************************************************************************/ +static inline void getscom_HW_ECID(uint64_t base, uint8_t* buf) { + uint64_t* buf64 = (uint64_t *) buf; + unsigned int i; +// uint64_t sum=0; // detect any change after fuse programming + for(i=0; i>16) != (~sum)) { +// ERROR_STOP(OTP_ECID_INVPOPSUM_CHECK,"Inverted Populationcount of ECID does not match"); +// } +} + +/****************************************************************************/ +static inline void getscom_PIBMEM_HW_Key_Hash(uint64_t base, uint8_t* buf) { + + uint64_t* buf64 = (uint64_t *) buf; + unsigned int i; + const unsigned int count = sizeof(sha2_hash_t)/sizeof(uint64_t); + uint64_t sum=0; // detect any change after fuse programming + for(i=0; i + +typedef uint8_t __attribute__((aligned(8))) sha2_hash_t[ SHA512_DIGEST_LENGTH / sizeof(uint8_t) ]; + +typedef uint8_t sha2_byte; /* Exactly 1 byte */ +typedef uint32_t sha2_word32; /* Exactly 4 bytes */ +typedef uint64_t sha2_word64; /* Exactly 8 bytes */ + +typedef struct _SHA512_CTX { + uint64_t state[8]; + uint64_t bitcount[2]; + uint8_t buffer[SHA512_BLOCK_LENGTH]; +} SHA512_CTX; + +void SHA512_Init(SHA512_CTX* context); +void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len); +void SHA512_Final(SHA512_CTX* context, sha2_hash_t *result); + +void SHA512_Hash(const sha2_byte *data, size_t len, sha2_hash_t *result); + +#endif diff --git a/src/include/securerom/status_codes.H b/src/include/securerom/status_codes.H new file mode 100644 index 00000000000..a2f94f59766 --- /dev/null +++ b/src/include/securerom/status_codes.H @@ -0,0 +1,113 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/include/securerom/status_codes.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/**************************************************************************** + * + ****************************************************************************/ +#ifndef STATUS_CODES_H +#define STATUS_CODES_H + +// Error extension code +#ifndef EMULATE_HW +#define ERROR_EVENT 0xFFFFFFFFFFFF8000 +#else +#define ERROR_EVENT 0xFFFFFFFFFFFF8000ull +#endif + +// context codes +#define ROM_INSTRUCTION_START 0x0100 +#define C_INSTRUCTION_START 0x0200 +#define ROM_SELFTEST 0x0300 +#define ROM_VERIFY 0x0400 +// documentaion 0x0600 C_INSTRUCTION_START call of ROM_VERIFY +#define ROM_SRESET 0x0E00 + +#define PHYP_VERIFY 0x1500 +#define PHYP_SHA512_HASH 0x1600 + +// progress/test codes +#define BEGIN 0x0001 + +#define TRUSTED_MEM_BAR 0x0012 + +#define CONTAINER_LOW_TEST 0x0013 + +#define XSCOM_LOW_TEST 0x0010 +#define XSCOM_VALID_TEST 0x0011 + +#define MAGIC_NUMBER_TEST 0x0020 +#define CONTAINER_VERSION_TEST 0x0021 +#define PREFIX_VER_ALG_TEST 0x0022 +#define HEADER_VER_ALG_TEST 0x0023 + +#define STACK_LOW_TEST 0x0030 +#define STACK_VALID_TEST 0x0031 +#define STACK_TRUST_TEST 0x0032 +#define STACK_ZERO_DONE 0x0033 + +#define SHA_GOOD_TEST 0x0040 +#define SHA_BAD_TEST 0x0041 +#define ECDSA_GOOD_TEST 0x0042 +#define ECDSA_BAD_TEST 0x0043 +#define SELFTEST_DONE 0x0044 + +#define TARGET_LOW_TEST 0x0050 +#define TARGET_VALID_TEST 0x0051 +#define TARGET_TRUST_TEST 0x0052 +#define STACK_VS_TARGET_TEST 0x0053 +#define TARGET_ZERO_DONE 0x0054 +#define CONTAINER_COPY_DONE 0x0055 + +#define HBI_KEY_TEST 0x0056 + +#define CONTAINER_VERIFY_DONE 0x0057 +#define STACK_CLEANUP_DONE 0x0058 + +#define OTP_ECID_INVPOPSUM_CHECK 0x0059 +#define OTP_KEY_INVPOPSUM_CHECK 0x005A + +#define HW_KEY_HASH_TEST 0x0060 +#define HW_SIGNATURE_TEST 0x0061 +#define PREFIX_ECID_TEST 0x0062 +#define PREFIX_HASH_TEST 0x0063 +#define SPECIAL_NO_ECID_TEST 0x0064 +#define SPECIAL_SIZE_0_TEST 0x0065 +#define SW_KEY_PROTECTION_TEST 0x0066 + +#define SW_SIGNATURE_TEST 0x0070 +#define HEADER_ECID_TEST 0x0071 +#define HEADER_HASH_TEST 0x0072 +#define CODE_PROTECTION_TEST 0x0073 + +#define ENTRY_VALID_TEST 0x0080 + +#define PARTIAL 0x0002 +#define COMPLETED 0x0003 + +#define EXECUTION_ERROR 0x00EE +#define XSCOM_ERROR 0xAFEE + +#define RETURNED_ERROR 0xD00F + +#endif diff --git a/src/securerom.ld b/src/securerom.ld new file mode 100644 index 00000000000..10670afe9e5 --- /dev/null +++ b/src/securerom.ld @@ -0,0 +1,96 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/securerom.ld $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/*****************************************************************************/ +/* linker script for low level firmware */ +/*****************************************************************************/ + +/* PH: to use the same lds file for 32/64bit, don't specify + * OUTPUT_FORMAT, OUTPUT_ARCH here. + * / + OUTPUT_FORMAT("elf64-powerpc") + OUTPUT_ARCH(powerpc64:common) + */ + +/* set the entry point */ +ENTRY(_instruction_start) + +MEMORY { + secure_boot_rom (IRX): ORIGIN = 0x80001C0000000000, LENGTH = 32K +/* untrusted_memory (RW): ORIGIN = 0x8000000000000000, LENGTH = 0x0000000000800000 +* trusted_memory (RW): ORIGIN = 0x8000000000800000, LENGTH = 0x800000FFFF800000 +*/ +} + + +SECTIONS { + . = 0x80001C0000000000; /* tbrom base address */ + + .branchtable : { + . = ALIGN(0x1000); + }>secure_boot_rom + + .text : { + *(.text) + }>secure_boot_rom + + . = ALIGN(8); + + __toc_start = .; + .toc : { + *(.toc .got) + }>secure_boot_rom + . = ALIGN(8); + __toc_end = .; + + .data : { + *(.data) + *(.rodata .rodata.*) + *(.got1) + *(.sdata) + }>secure_boot_rom + + . = ALIGN(8); + + /* PH: opd section must be separate, if i put it in .data, + * the C functions are not present in the generated file.... + * If anybody can explain why, i'd be glad to hear... + * Note: the KEEP has been removed was: " KEEP (*(.opd)) " + */ + .opd ALIGN(8) : { + *(.opd) + }>secure_boot_rom + + . = ALIGN(8); + __bss_start = .; + .bss : { + *(.sbss) *(.scommon) + *(.dynbss) + *(.bss) + }>secure_boot_rom + . = ALIGN(8); + __bss_end = .; + __bss_size = SIZEOF(.bss); + +} diff --git a/src/securerom/ROM.C b/src/securerom/ROM.C new file mode 100644 index 00000000000..2f73a5da577 --- /dev/null +++ b/src/securerom/ROM.C @@ -0,0 +1,579 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/securerom/ROM.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/**************************************************************************** + * + ****************************************************************************/ +#ifndef PHYPLIBFUNCTIONS +#include +#endif +#include +#include +#include + +/****************************************************************************/ +#define valid_magic_number(header) (GET32((header)->magic_number) == ROM_MAGIC_NUMBER) +#define valid_container_version(header) (GET16((header)->version) == CONTAINER_VERSION) + +/****************************************************************************/ +static int valid_ver_alg(ROM_version_raw* ver_alg, uint8_t sig_alg) { + if (GET16(ver_alg->version) != HEADER_VERSION) return 0; + if (ver_alg->hash_alg != HASH_ALG_SHA512) return 0; + if (!sig_alg) return 1; + if (ver_alg->sig_alg != sig_alg) return 0; + return 1; +} + +/****************************************************************************/ +static int valid_ecid(int ecid_count, uint8_t* ecids, uint8_t* hw_ecid) { + if (!ecid_count) return 1; + for (;ecid_count;ecid_count--,ecids+=ECID_SIZE) + if (!memcmp (hw_ecid, ecids, ECID_SIZE)) return 1; + return 0; +} + +/****************************************************************************/ +static int multi_key_verify(uint8_t* digest, int key_count, uint8_t* keys, uint8_t* sigs) { + for (;key_count;key_count--,keys+=sizeof(ecc_key_t),sigs+=sizeof(ecc_signature_t)) + if (ec_verify (keys, digest, sigs)<1) return 0; + return 1; +} + +#ifndef PHYPLIBFUNCTIONS +/****************************************************************************/ +static inline ROM_container_raw* cast_container(uint64_t addr) { + return (ROM_container_raw*) Convert_Mem_Addr(physical_addr(addr)); +} + +/****************************************************************************/ +static inline void ROM_init_cache_area(uint64_t target, uint64_t size) { + uint64_t i; + for (i=0;i0;size-=sizeof(uint64_t)) { + *dst++ = *src++; + } + assem_SYNC(); //heavy weight form of sync instruction + //which ensures all stores have been performed + //prior to the subsequent icbi + assem_ICBI(to); //only need one of these to any address.... + //this is only needed to set internal scoreboard bit + //to tell the processor to flush + //when it sees a subsequent isync + assem_ISYNC(); +} + +//extern void* __toc_start; + +#if 0 + +#define STACK_ASSUMPTION 128*1024 +#define STACK_FRAME (2*8) +/****************************************************************************/ +#undef CONTEXT +#define CONTEXT ROM_INSTRUCTION_START +/****************************************************************************/ +static inline void Create_C_Environment(uint64_t stack) { + #ifdef EMULATE_HW + printf ("Creating C Environment with stack pointer 0x%016llX\n",stack); + #else + // zero (create) stack area + ROM_init_cache_area(stack-STACK_ASSUMPTION, STACK_ASSUMPTION); + LOG(STACK_ZERO_DONE); + + // set stackpointer + register volatile uint64_t r1 __asm__ ("r1"); // if you remove the volatile keyword then the compiler removes your code - grr + r1 = stack-8; + //*((uint64_t*)stack) = 0ull; -- end stackframe --already 0 by dcbz above + + //setup initial stackframe + asm("stdu r1, -56(r1)"); + + #endif +} + +static inline void initTOCpointer() { + #ifdef EMULATE_HW + printf ("Initialize r2 with TOC pointer\n"); + #else + // set TOC pointer (unused because no global variables) + // register uint64_t r2 __asm__ ("r2"); + // r2 = (uint64_t)__toc_start+0x8000; //only for one TOC + // r2 = ((uint64_t*)&ROM_instruction_start)[1]; //saver to get from { entry_point, toc_base, environment } + asm( + "springboard2: \n" + " b boingboing2 \n" // set CFAR + "boingboing2: \n" + " mfspr r2, 28 \n" // mfCFAR get address of springboard2 + " addi r2, r2, 0x4000 \n" // adjust to __toc_start (part 1) + " addi r2, r2, (__toc_start+0x4000-springboard2)@l \n" // adjust to __toc_start (part 2) + ); + #endif +} + +/****************************************************************************/ +#undef CONTEXT +#define CONTEXT ROM_SELFTEST +/****************************************************************************/ +static void ROM_selftest(void) { +#ifndef EMULATE_HW + selftest_t const *selftest_p; + asm volatile("li %0,(__toc_start)@l ### %0 := base+0x8000 \n\t" // because li does not work + "sub %0,r2,%0 \n\t" // because subi does not work + "addi %0,%0,(selftest-0x8000)@l" : "=r" (selftest_p) ); +#else + selftest_t const *selftest_p = &selftest; //this line would introduce a absolute address in the toc +#endif + + sha2_hash_t digest; + LOG(BEGIN); + // sha512 good selftest + SHA512_Hash((uint8_t*)&selftest_p->ec, sizeof(selftest_p->ec), &digest); + if(memcmp(digest, selftest_p->sha.hash, sizeof(sha2_hash_t))) + ERROR_STOP(SHA_GOOD_TEST,"sha512 good selftest failed"); + // sha512 bad selftest + SHA512_Hash((uint8_t*)&selftest_p->ec, sizeof(selftest_p->ec)-1, &digest); + if(!memcmp (digest, selftest_p->sha.hash, sizeof(sha2_hash_t))) + ERROR_STOP(SHA_BAD_TEST,"sha512 bad selftest failed"); + // ecdsa verify good selftest + if (ec_verify (selftest_p->ec.pkey, selftest_p->ec.hash, selftest_p->ec.sig)<1) + ERROR_STOP(ECDSA_GOOD_TEST,"ecdsa good selftest failed"); + // ecdsa verify bad selftest (use digest from sha512 bad test) + if (ec_verify (selftest_p->ec.pkey, digest, selftest_p->ec.sig)!=0) + ERROR_STOP(ECDSA_BAD_TEST,"ecdsa bad selftest failed"); +} + +/****************************************************************************/ +#undef CONTEXT +#define CONTEXT C_INSTRUCTION_START +/****************************************************************************/ +uint64_t C_instruction_start( uint64_t xscom + , uint64_t fsp_bar + , uint64_t stack + , ROM_container_raw* container + ) { + LOG(BEGIN); + + // run crypto selftests + ROM_selftest(); + LOG(SELFTEST_DONE); + + // test for valid target hrmor address in trusted memory (security checks) + uint64_t target_hrmor = GET64(container->target_hrmor); + if(target_hrmor < 4096) + ERROR_STOP(TARGET_LOW_TEST,"target hrmor too low"); + if(target_hrmor & ~HRMOR_MASK) + ERROR_STOP(TARGET_VALID_TEST,"invalid target hrmor address"); + if(physical_addr(target_hrmor-4096)container_size); + if( stack > target_hrmor-4096 + && stack-STACK_ASSUMPTION <= target_hrmor+size + ) + ERROR_STOP(STACK_VS_TARGET_TEST,"container vs stack collision"); + + mtspr_HRMOR(target_hrmor); + + // clear ERATS because hrmor has changed + #ifdef EMULATE_HW + printf ("clear ERATS because hrmor has changed\n"); + #else + asm volatile ("slbia"); + #endif + + // zero target area and copy container + ROM_init_cache_area(target_hrmor-4096, size); + LOG(TARGET_ZERO_DONE); + ROM_container_raw* target = cast_container(target_hrmor-4096); + ROM_memcpy_icbi((uint64_t*)target, (uint64_t*)container, size); + LOG(CONTAINER_COPY_DONE); + + // test for prefix header with HBI base code (firmware) signing keys + ROM_prefix_header_raw* prefix = (ROM_prefix_header_raw*) &target->prefix; + if(!valid_ver_alg(&prefix->ver_alg, SIG_ALG_ECDSA521)) + ERROR_STOP(PREFIX_VER_ALG_TEST,"bad prefix header version,alg's"); + uint32_t flags = GET32 (prefix->flags); + if(!(flags & HBI_BASE_SIGNING_KEY)) + ERROR_STOP(HBI_KEY_TEST,"not HBI base code key prefix"); + + // verify + + // fill verify hw params + ROM_hw_params params; + getscom_PIBMEM_HW_Key_Hash(xscom, params.hw_key_hash); + getscom_HW_ECID(xscom, params.my_ecid); + if (ROM_verify(target,¶ms) != ROM_DONE) + ERROR_STOP(params.log,"see above"); // this will added C_INSTRUCTION_START to ROM_VERIFY for 0600 + LOG(CONTAINER_VERIFY_DONE); + + return HRMOR_RELATIVE(params.entry_point); +} + +#endif + +/****************************************************************************/ +#undef CONTEXT +#define CONTEXT ROM_SRESET +/****************************************************************************/ +#ifdef EMULATE_HW +void ROM_sreset (void) { +#else +void ROM_sreset(void) { + asm volatile (".globl rom_sreset\n rom_sreset:"); //skip prologue +#endif + // should never get here unless started too soon by fsp/sbe, checkstop + ERROR_STOP(EXECUTION_ERROR,"sreset"); +} + +#if 0 +/****************************************************************************/ +#undef CONTEXT +#define CONTEXT ROM_INSTRUCTION_START +/****************************************************************************/ +//static inline void ROM_Cleanup_Stack(uint64_t stack) { +//#ifdef EMULATE_HW +// printf ("Cleaning up stack\n"); +//#endif +// ROM_invalidate_cache_area(stack-STACK_ASSUMPTION, STACK_ASSUMPTION); +//} + +/****************************************************************************/ +#ifdef EMULATE_HW +static void Call_Entry_Point(uint64_t start) { + printf ("Branching to entry point 0x%016llX (PHY 0x%016llX)\n",start,physical_addr(start)); + return; +#else +static void __attribute__((noreturn)) Call_Entry_Point(uint64_t start) { + + asm volatile ( " mtctr %0 \n" + " bctr \n" + " nop " + : // no output + : "r" (start) // input, %0 + // no impacts ? + ); + + ERROR_STOP(RETURNED_ERROR,"returned from Entry_Point"); + #if !defined(_lint_) + for (;;); + #endif +#endif +} + +/* Check the maximum limit of a untrusted memory BAR + * + * A BAR are two SCOM register one containing a mask and the other the pattern + * the address is in the untrusted memory when this is true: + * (address & mask) == pattern + * If this is true then a untrusted PIB master (like FSI) can write it. + * Remark: + * If a mask bit is 0 and the coresponding pattern bit is 1 then it is always false. + * + * parameter: + * limit = previous limit from other BARs or 0 + * xscom = the xscom base address + * bar = the pib address of the BAR register containing the pattern + * barMask = the pib address of the BAR register containing the mask + * return value: + * the new limit is the maximum from previous limit and the bars limit + */ +uint64_t check_bar(uint64_t limit, uint64_t xscom, uint64_t bar, uint64_t barMask) { + uint64_t barValue = getscom(xscom,bar); + uint64_t barMaskValue = getscom(xscom,barMask); + + barMaskValue |= 0xFFFC000000000000; // bit 0:13 not implemented and must be '1' + + uint64_t barLimit = (barValue | ~barMaskValue) + 1; + if( ( (barValue & ~barMaskValue) == 0) + && ( barLimit > limit) + ) { + limit=barLimit; + } + return limit; +} + +#endif + +/****************************************************************************/ +#ifdef EMULATE_HW +void ROM_instruction_start(void) { +#else +void __attribute__((noreturn)) ROM_instruction_start(void) { + asm volatile (".globl instruction_start\ninstruction_start:"); //skip prologue +#endif + +#if 0 + + initTOCpointer(); + + LOG(BEGIN); + + // test for reasonable xscom base address (security check) + register uint64_t xscom = mfspr_SCRATCH0(); + if(!xscom) { + ERROR_STOP(XSCOM_LOW_TEST,"xscom base address too low"); + } + if(xscom & ~XSCOM_MASK) { + ERROR_STOP(XSCOM_VALID_TEST,"invalid xscom base address"); + } + xscom = ABSOLUTE_ADDR(xscom); + +#ifndef EMULATE_HW + // get trusted memory base + uint64_t fsp_bar=0; + fsp_bar = check_bar(fsp_bar, xscom, ALTD_UNTRUSTED_BAR_ADDR_REG, ALTD_UNTRUSTED_BAR_MASK_ADDR_REG); + fsp_bar = check_bar(fsp_bar, xscom, PSIHB_NOTRUST_BAR0, PSIHB_NOTRUST_BAR0MASK ); + fsp_bar = check_bar(fsp_bar, xscom, PSIHB_NOTRUST_BAR1, PSIHB_NOTRUST_BAR1MASK ); +#else + // get trusted memory base + uint64_t fsp_bar = (getscom_FSP_BAR_value(xscom) | ~getscom_FSP_BAR_mask(xscom)) + 1; +#endif + + LOG(TRUSTED_MEM_BAR); + + register uint64_t raw_container = mfspr_SCRATCH1(); + if (raw_container < 4096) //must check for value that will wrap around + ERROR_STOP(CONTAINER_LOW_TEST,"container too low"); + raw_container = ABSOLUTE_ADDR(raw_container)-4096; + ROM_container_raw* container = cast_container(raw_container); + + // test for valid container magic number, version, hash & signature algorithms (sanity checks) + if(!valid_magic_number(container)) + ERROR_STOP(MAGIC_NUMBER_TEST,"bad container magic number"); + if (!valid_container_version (container)) + ERROR_STOP(CONTAINER_VERSION_TEST,"bad container version"); + + // test for trusted memory stack pointer (assumes 8K max depth) + register uint64_t stack = GET64(container->stack_pointer); + stack += STACK_ASSUMPTION; + if(stack < STACK_ASSUMPTION) { + ERROR_STOP(STACK_LOW_TEST,"stack pointer too low"); + } + if(stack & ~STACK_MASK) + ERROR_STOP(STACK_VALID_TEST,"invalid stack pointer address"); + if(physical_addr(stack-STACK_ASSUMPTION)log=ERROR_EVENT|CONTEXT|(_c); printf ("FAILED '%s'\n", (_m)); return ROM_FAILED; } +#else + #define FAILED(_c,_m) { params->log=ERROR_EVENT|CONTEXT|(_c); return ROM_FAILED; } +#endif + +//**************************************************************************** +#undef CONTEXT +#ifndef PHYPLIBFUNCTIONS +#define CONTEXT ROM_VERIFY +//**************************************************************************** +// NOTE: ROM_verify is called with absolute addresses from c_instruction_start +// and with hrmor relative addresses from Hostboot +asm(".globl .L.ROM_verify"); +ROM_response ROM_verify( ROM_container_raw* container, + ROM_hw_params* params ) { +#else +#define CONTEXT PHYP_VERIFY +//**************************************************************************** +// NOTE: PHYP_verify is called with hrmor relative addresses from PHYP +ROM_response PHYP_verify( PHYP_command cmnd, + ROM_container_raw* container, + PHYP_hw_params* params, + PHYP_verify_state* state ) { +#endif + sha2_hash_t digest; + ROM_prefix_header_raw* prefix; + ROM_prefix_data_raw* hw_data; + ROM_sw_header_raw* header; + ROM_sw_sig_raw* sw_sig; + uint64_t size; + + params->log=CONTEXT|BEGIN; + +#ifdef PHYPLIBFUNCTIONS + if(cmnd != PHYP_CONTINUE) { +#endif + // test for valid container magic number, version, hash & signature algorithms (sanity check) + if(!valid_magic_number(container)) + FAILED(MAGIC_NUMBER_TEST,"bad container magic number"); + if(!valid_container_version(container)) + FAILED(CONTAINER_VERSION_TEST,"bad container version"); +#ifdef PHYPLIBFUNCTIONS + // initialize verify state + state->state = PHYP_START_VERIFY; + } + + do { + switch(state->state) { + case PHYP_START_VERIFY: +#endif + // process hw keys + // test for valid hw keys + SHA512_Hash(container->hw_pkey_a, 3*sizeof(ecc_key_t), &digest); + if(memcmp(params->hw_key_hash, digest, sizeof(sha2_hash_t))) + FAILED(HW_KEY_HASH_TEST,"invalid hw keys"); + + // process prefix header + prefix = (ROM_prefix_header_raw*) &container->prefix; + // test for valid header version, hash & signature algorithms (sanity check) + if(!valid_ver_alg(&prefix->ver_alg, SIG_ALG_ECDSA521)) + FAILED(PREFIX_VER_ALG_TEST,"bad prefix header version,alg's"); + // test for valid prefix header signatures (all) + hw_data = (ROM_prefix_data_raw*) (prefix->ecid + prefix->ecid_count*ECID_SIZE); + SHA512_Hash((uint8_t*)prefix, PREFIX_HEADER_SIZE(prefix), &digest); + if(!multi_key_verify(digest, 3, container->hw_pkey_a, hw_data->hw_sig_a)) + FAILED(HW_SIGNATURE_TEST,"invalid hw signature"); + // test for machine specific matching ecid + if(!valid_ecid(prefix->ecid_count, prefix->ecid, params->my_ecid)) + FAILED(PREFIX_ECID_TEST,"unauthorized prefix ecid"); + // test for valid prefix payload hash + size = GET64(prefix->payload_size); + SHA512_Hash(hw_data->sw_pkey_p, size, &digest); + if(memcmp(prefix->payload_hash, digest, sizeof(sha2_hash_t))) + FAILED(PREFIX_HASH_TEST,"invalid prefix payload hash"); + // test for special prefix header + if(!prefix->sw_key_count) { + // finish processing special prefix header + // test for machine specfic (sanity check) + if(prefix->ecid_count == 0) + FAILED(SPECIAL_NO_ECID_TEST,"special prefix with ecid_count == 0"); + // test for signing of keys only (sanity check) + if(size != 0) + FAILED(SPECIAL_SIZE_0_TEST,"special prefix with payload_size != 0"); + // return hrmor relative code start address + params->entry_point = GET64(prefix->code_start_offset); + //check if the entry is HRMOR-relative and aligned + if(params->entry_point & ~(ENTRY_MASK)) + FAILED(ENTRY_VALID_TEST,"entry is not HRMOR relative or not aligned"); + params->log=CONTEXT|COMPLETED; + return ROM_DONE; + } + // finish processing prefix header + // test for protection of all sw key material (sanity check) + if(size != (prefix->sw_key_count * sizeof(ecc_key_t))) + FAILED(SW_KEY_PROTECTION_TEST,"incomplete sw key protection in prefix header"); + + // start processing sw header + header = (ROM_sw_header_raw*) (hw_data->sw_pkey_p + prefix->sw_key_count*sizeof(ecc_key_t)); + // test for valid header version, hash & signature algorithms (sanity check) + if(!valid_ver_alg(&header->ver_alg, 0)) + FAILED(HEADER_VER_ALG_TEST,"bad sw header version,alg"); + // test for valid sw header signatures (all) + sw_sig = (ROM_sw_sig_raw*) (header->ecid + header->ecid_count*ECID_SIZE); + SHA512_Hash((uint8_t*)header, SW_HEADER_SIZE(header), &digest); + if(!multi_key_verify(digest, prefix->sw_key_count, hw_data->sw_pkey_p, sw_sig->sw_sig_p)) + FAILED(SW_SIGNATURE_TEST,"invalid sw signature"); + // test for machine specific matching ecid + if(!valid_ecid(header->ecid_count, header->ecid, params->my_ecid)) + FAILED(HEADER_ECID_TEST,"unauthorized sw ecid"); + // test for entry point within protected payload (sanity check) + params->entry_point = GET64(header->code_start_offset); + //check if the entry is HRMOR-relative and aligned + if(params->entry_point & ~(ENTRY_MASK)) + FAILED(ENTRY_VALID_TEST,"entry is not HRMOR relative or not aligned"); + size = GET64(header->payload_size); + if(params->entry_point+3 >= size) // must have full instruction (3 more bytes) + FAILED(CODE_PROTECTION_TEST,"unprotected code_start in sw header"); + // begin test for valid sw payload hash +#ifdef PHYPLIBFUNCTIONS + state->message = (uint8_t*)container + 4096; + state->remain = size; + SHA512_Init(&state->sha); + state->header = header; + state->state = PHYP_CONT_VERIFY; + params->log=CONTEXT|PARTIAL; + break; + + case PHYP_CONT_VERIFY: + if(state->remain > params->max_hash) { + // continue test for valid sw payload hash + SHA512_Update(&state->sha, state->message, params->max_hash); + state->message += params->max_hash; + state->remain -= params->max_hash; + } else { + // finish test for valid sw payload hash + SHA512_Update(&state->sha, state->message, state->remain); + SHA512_Final(&state->sha, &digest); + header = state->header; +#else + SHA512_Hash((uint8_t*)container + 4096, size, &digest); +#endif + if(memcmp(header->payload_hash, digest, sizeof(sha2_hash_t))) + FAILED(HEADER_HASH_TEST,"invalid sw payload hash"); + params->log=CONTEXT|COMPLETED; + return ROM_DONE; +#ifdef PHYPLIBFUNCTIONS + } + break; + + default: + FAILED(EXECUTION_ERROR,"bad internal state"); + break; + } + } while (cmnd == PHYP_WHOLE); + params->log=CONTEXT|PARTIAL; + return PHYP_PARTIAL; +#endif +} diff --git a/src/securerom/branchtable.S b/src/securerom/branchtable.S new file mode 100644 index 00000000000..d3c1c86084a --- /dev/null +++ b/src/securerom/branchtable.S @@ -0,0 +1,98 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/securerom/branchtable.S $ +# +# OpenPOWER HostBoot Project +# +# Contributors Listed Below - COPYRIGHT 2016,2017 +# [+] International Business Machines Corp. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. See the License for the specific language governing +# permissions and limitations under the License. +# +# IBM_PROLOG_END_TAG +#**************************************************************************** +#* branch table - a more stable location for software entering rom code +#**************************************************************************** +# adr function +# 0 instruction_start +# 2 .SHA512_Init +# 4 .SHA512_Update +# 6 .SHA512_Final +# 8 .SHA512_Hash +# A .ec_verify +# C .ROM_verify +# 100 rom_sreset + +branchtable: + .section ".branchtable","ax" + + .globl _instruction_start +_instruction_start: + b instruction_start + nop + + .globl _SHA512_Init +_SHA512_Init: + li r0, .L.SHA512_Init@l + b springboard + + .globl _SHA512_Update +_SHA512_Update: + li r0, .L.SHA512_Update@l + b springboard + + .globl _SHA512_Final +_SHA512_Final: + li r0, .L.SHA512_Final@l + b springboard + + .globl _SHA512_Hash +_SHA512_Hash: + li r0, .L.SHA512_Hash@l + b springboard + + .globl _ec_verify +_ec_verify: + li r0, .L.ec_verify@l + b springboard + + .globl _ROM_verify +_ROM_verify: + li r0, .L.ROM_verify@l + b springboard + +#define CFAR 28 + +springboard: + b boingboing +boingboing: + mfspr r2, CFAR // get address of springboard + addi r2, r2, _instruction_start-springboard // base address + add r0, r0, r2 // calculate entry relative + addi r2, r2, 0x4000 //TOC+0x8000 part 1 + addi r2, r2, (__toc_start+0x4000)@l //TOC+0x8000 part 2 + mtctr r0 + bctr // jump + +# could put other assembly ocde routines here to conserver ROM space +# including the sreset routine + +# need to align on bootrombase+0x100 !!! + .org .branchtable+0x100 + .globl _rom_sreset +_rom_sreset: + li r0, rom_sreset@l + b springboard + nop diff --git a/src/securerom/ecverify.C b/src/securerom/ecverify.C new file mode 100644 index 00000000000..659d7d6fb69 --- /dev/null +++ b/src/securerom/ecverify.C @@ -0,0 +1,1662 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/securerom/ecverify.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/*---------------------------------------------------------------------- + * (C) COPYRIGHT INTERNATIONAL BUSINESS MACHINES CORPORATION 2010 + * ALL RIGHTS RESERVED + * IBM Research, Zurich and IBM Crypto Competency Center, Copenhagen + *---------------------------------------------------------------------- + * Author: Tamas Visegrady (tvi@zurich.ibm.com) + * Change: W Eric Hall (wehall@us.ibm.com) + *----------------------------------------------------------------------*/ + +/** ECDSA verification on fixed curve/s (currently, on NIST P-521) + * The code below works for a compile-time constant curve, and requires + * a single bignumber pair (public key) to specify a key + * + * Knowledge of our environment allows the following simplifications: + * - modular operations are always mod P + * - there (multiple) unused bits in the most significant word of bignums + * Further assumptions: + * - bignumber indices fit 7 bits (8-bit counter sufficient for double bn's) + * Search for "P521", which flags curve dependencies. + */ + + +#define __STDC_FORMAT_MACROS 1 /* add 64-bit printf modifiers */ +#include +#include +#include /* uint_fast8_t, uintN_t */ +#include /* PRIx64 used to format bn_t's */ + +/** + * Define __LITTLE_ENDIAN or __BIG_ENDIAN for target. + */ +#if defined __BIG_ENDIAN__ || defined _BIG_ENDIAN + #define __BIG_ENDIAN + #undef __LITTLE_ENDIAN +#else + #undef __BIG_ENDIAN + #define __LITTLE_ENDIAN +#endif + +#include "ecverify.h" + + +#define EC_PRIMEBITS 521 /* P521 */ + +//#define EC_DEBUG 1 /* needs libc (not in Prism version) */ +#define EC_STACKTRACE 1 /* debug only; currently, glibc */ +#define NO_EC_DOUBLE_XY 1 /* do not implement ec_double_xy */ + +typedef uint64_t bn_t; +typedef uint32_t hbn_t; /* half-bignumber */ +typedef uint_fast8_t bnindex_t; + +#define BN_FMT "%016" PRIx64 /* PRIx64 from inttypes.h */ + + +// show word boundaries in bignumbers (diagnostics dump only) +// #define EC_DEBUG_WORDS 1 + + +// define this if we construct ec_prime[] on the fly +// saves code, adds runtime static structs; check your compiler if useful +// does not make sense if non-exec, read-only constants are cheap +// +// #define BN_PRIME_GENERATED 1 + + +//--- nothing user-servicable below --------------------------------------- + +#if !defined(__LITTLE_ENDIAN) && !defined(__BIG_ENDIAN) +#error "Please define target endianness (__LITTLE_ENDIAN or __BIG_ENDIAN)" +#endif + +#if defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN) +#error "Please define one target endianness (__LITTLE_ENDIAN or __BIG_ENDIAN)" +#endif + + +#define BN_BITS (8*sizeof(bn_t)) +#define HBN_BITS (8*sizeof(hbn_t)) + +#define EC_PRIMEBYTES ((EC_PRIMEBITS +7) /8) + +#define BN_MAXBIT (((bn_t) 1) << (BN_BITS -1)) + +#define BITS2BN(bits) \ + (((bits) +BN_BITS -1) / BN_BITS) + +// we only deal with big numbers of fixed size +#define NWORDS BITS2BN( EC_PRIMEBITS ) +#define BNBYTES (NWORDS*sizeof(bn_t)) + +#define BN_MSW(p) ((p)[0]) +#define BN_LSW(p) ((p)[ NWORDS-1 ]) +#define bn_is_odd(p) (1 & BN_LSW(p)) + + +#ifndef BN_POWER64_CPY +#define BN_COPY(dst, src) memcpy((dst), (src), NWORDS*sizeof(bn_t)) +#else +static void __attribute__((noinline)) BN_COPY (bn_t *dst, const bn_t *src) +{ + size_t i; + for(i=0;iec_prime) >= 0) +#define bn_ge_order(val) (bn_cmp((val), consts_p()->ec_order) >= 0) + + +//------------------------------------- +// P521: MSW has unused bits +#define BN_MSW_UNUSED_BITS (BN_BITS - BN_PRIME_MSW_BITS) +#define BN_MSW_UNUSED_BYTES ((BN_MSW_UNUSED_BITS +7) >>3) +#define BN_MSW_UNUSED_MASK ((((bn_t) 1) << BN_MSW_UNUSED_BITS) -1) + +// not general-purpose shl: we only need to shift products (2*NWORDS) +// to two EC_PRIMEBITS, with BN_MSW_UNUSED_BITS +// +// acc contains MSW of lower half +// +static bn_t bn_shl (bn_t *a, bn_t acc) +{ + bnindex_t i = NWORDS; + bn_t cf = 0; + + EC_ASSERT(NULL != a); + EC_ASSERT(0 == a[0]); + + a += NWORDS; + + while (0> BN_PRIME_MSW_BITS); + + acc = cf; + } + + return cf; +} + + +//========================================================= diagnostics ==== +#if defined(EC_DEBUG) + +static void bn_printn (const char *msg, const bn_t *m, bnindex_t i) +{ + EC_ASSERT(NULL != m); + + if (NULL != msg) + printf("%s", msg); + + while (0 < i--) { +#if defined(EC_DEBUG_WORDS) + if (i> HBN_BITS); + bl = b; + bh = (hbn_t) (b >> HBN_BITS); + + a = ((bn_t) ah) * bh; // collects high word + b = ((bn_t) al) * bl; // collects low word + + t = ((bn_t) ah) * bl; + a += t >> HBN_BITS; + t <<= HBN_BITS; + if (b+t < t) + ++a; + b += t; + + t = ((bn_t) al) * bh; + a += t >> HBN_BITS; + t <<= HBN_BITS; + if (b+t < t) + ++a; +// b += t; // we don't actually need this, only its carry above + return a; +#endif +} + + +//------------------------------------- +/** multiply (a,NWORDS) by (b,NWORDS) into (r,2*NWORDS) + * we collect 2-word multiples, and carries across columns in two + * arrays: + * + * products + * a[0].b[0] a[1].b[0] a[2].b[0] + * a[0].b[1] a[1].b[1] + * a[0].b[2] + * carry in column to: + * carry[0] carry[1] carry[2]... + * + * delaying carry-collection simplifies multiply loop + */ +// XXX split to half-words' array; get rid of bn_dmul() +// +static void bn_mul (bn_t *r, const bn_t *a, const bn_t *b) +{ + unsigned char cf[ NWORDS+NWORDS ]; /* carry collector */ + bnindex_t i, j; + bn_t ph, pl; /* product high,low words */ + + EC_ASSERT(NULL != r); + EC_ASSERT(NULL != a); + EC_ASSERT(NULL != b); + + bn_dclear(r); + memset(cf, 0, sizeof(cf)); + + for (j=0; j0); // MSW can't carry to left + (cf[i+j-1])++; + } + + r[i+j+1] += pl; + if (r[i+j+1] < pl) + (cf[i+j])++; +#endif + } + } + + // propagate carries (LS to MS) +#ifdef EC_POWER64_ASM + i=NWORDS+NWORDS-2; + asm("addc %0,%1,%2" + : "=r" (r[i]) + : "0" (r[i]), "r" (cf[i+1]) + ); + for ( ; 0ec_prime) >= 0) + bn_sub(rc, consts_p()->ec_prime); // XXX can this happen? (mod-based input) + + if (bn_cmp(al, consts_p()->ec_prime) >= 0) + bn_sub(al, consts_p()->ec_prime); + EC_ASSERT(!bn_ge_prime(al)); // al must have bitlen <= ec_prime + + bn_add(rc, al); + if (bn_cmp(rc, consts_p()->ec_prime) >= 0) + bn_sub(rc, consts_p()->ec_prime); +} +#else +#ifdef BN_POWER64_SQR +static void __attribute__((noinline)) bn_modred_fast (bn_t *r, bn_t *a) +#else +static void bn_modred_fast (bn_t *r, bn_t *a) +#endif +{ + bn_t *ah = a + NWORDS; + bn_t *al = a + 2*NWORDS; + bn_t t0 = (*(a+1) >> 18) + (*ah >> 9); + bn_t t1, t2, t3=0; + size_t i; + r += NWORDS; + for (i=0; i> 9; + asm("addc %3,%7,%5\n" //t3 = *(--al) + t0; + "addze %2,%6\n" //t2 += ca; + "addc %0,%4,%8\n" //*(--r) = t3 + t1; + "addze %1,%6" //t0 = t2 + ca; + : "=r" (*(--r)), "=r" (t0), "=r" (t2), "=r" (t3) + : "3" (t3), "1" (t0), "2" (t2), "r" (*(--al)), "r" (t1) + ); + } + t1 = *(--ah) << 55; + t2 = (*ah >> 9)&BN_PRIME_MSW_MASK; + asm("addc %3,%7,%5\n" //t3 = *(--al) + t0; + "addze %2,%6\n" //t2 += ca; + "addc %0,%4,%8\n" //*(--r) = t3 + t1; + "addze %1,%6" //t0 = t2 + ca; + : "=r" (*(--r)), "=r" (t0), "=r" (t2), "=r" (t3) + : "3" (t3), "1" (t0), "2" (t2), "r" (*(--al)), "r" (t1) + ); + *(--r) = (*(--al)&BN_PRIME_MSW_MASK) + t0; +} + +static void __attribute__((noinline)) bn_modred_slow (bn_t *r) +{ + size_t i; + if (*r > BN_PRIME_MSW_MASK) { + bn_t t0 = *r >> 9; + *r &= BN_PRIME_MSW_MASK; + r += NWORDS; + asm("addc %0,%1,%2" + : "=r" (*r) + : "0" (*(--r)), "r" (t0) + ); + for (i=0; iec_prime); +} +#endif + + +static void bn_modmul_prime (bn_t *a, const bn_t *b) +{ + bn_t prod[ NWORDS+NWORDS ]; + + EC_ASSERT(NULL != a); + EC_ASSERT(NULL != b); + + bn_mul(prod, a, b); +#ifdef EC_POWER64_RED + bn_modred_fast(a, prod); // accepts upto 46 extra bits => outputs at most 1 extra bit (522) +#else + bn_modred_p521(a, prod); +#endif +} + +#ifdef EC_POWER64_ALG +static void bn_modsqr_prime (bn_t *a) +{ +#ifdef BN_POWER64_SQR + bn_t prod[ NWORDS+NWORDS ]; + + EC_ASSERT(NULL != a); + + bn_sqr(prod, a); +#ifdef EC_POWER64_RED + bn_modred_fast(a, prod); // accepts upto 46 extra bits => outputs at most 1 extra bit (522) +#else + bn_modred_p521(a, prod); +#endif +#else + bn_modmul_prime(a, a); +#endif +} +#endif + + + +// mod reduce 2*NWORDS to NWORDS through approximate division +// +// input (a,2*NWORDS) <= N^2 -2*N +1 +// +// N = 2^521 -Q (Q is approx 2^260) +// A = AH * 2^521 + AL (AH < 2^251) +// A/N = (AH*R + AL)/N = AH + (AH*Q + AL) /N ~ AH + (AH*Q /N) +// AH*Q /N =~ AH* floor(Q/N) +// +// dividend may be two too low: +// 1. we neglect AL/N, which may add add one (ALec_order_qn); + bn_shl(dbl, dbl[NWORDS]); // MS 521 bits of product + bn_add(r, dbl); + + bn_mul(dbl, r, consts_p()->ec_order); // N * floor(A / N) + EC_ASSERT(bn_cmp(dbl, a) <= 0); + EC_ASSERT(bn_cmp(dbl+NWORDS, a+NWORDS) <= 0); + + BN_COPY(r, a+NWORDS); + bn_sub(r, dbl+NWORDS); // A - (N * floor(A/N)) + + if (bn_cmp(r, consts_p()->ec_order) >= 0) + bn_sub(r, consts_p()->ec_order); + + if (bn_cmp(r, consts_p()->ec_order) >= 0) + bn_sub(r, consts_p()->ec_order); // XXX can this still be 2+ over? + + EC_ASSERT(bn_cmp(r, consts_p()->ec_order) < 0); +} + + +static void bn_modmul_order (bn_t *a, const bn_t *b) +{ + bn_t prod[ NWORDS+NWORDS ]; + + EC_ASSERT(NULL != a); + EC_ASSERT(NULL != b); + + bn_mul(prod, a, b); + bn_modred_p521_order(a, prod); +} + + +//------------------------------------- +// negative,0,positive for ab +// +#if defined(__BIG_ENDIAN) && !defined(BN_POWER64_CMP) + +static int bn_cmp (const bn_t *a, const bn_t *b) +{ + EC_ASSERT(NULL != a); + EC_ASSERT(NULL != b); + + return memcmp(a, b, sizeof(bn_t)*NWORDS); +} + +#else /* defined(__BIG_ENDIAN) */ + +static int __attribute__((noinline)) bn_cmp (const bn_t *a, const bn_t *b) +{ + bnindex_t i; + + EC_ASSERT(NULL != a); + EC_ASSERT(NULL != b); + + for (i=0; i 0) { + if (0 != *p2) + return !(0 - *p2); + p2 += 1; + } + + return !0; + +// replaces: +// return !memcmp(bn_zero, m, sizeof(bn_t)*(NWORDS-mn)); +} + + +//------------------------------------- +static void __attribute__((noinline)) bn_add (bn_t *a, const bn_t *b) +{ + bn_t aw, cf = 0; /* aw: copy of current word to allow a==b */ + bnindex_t i = NWORDS; + + EC_ASSERT(NULL != a); + EC_ASSERT(NULL != b); + + a += NWORDS-1; + b += NWORDS-1; + + while (0 < i--) { + aw = *a; + if (cf) + cf = (0 == ++aw); + + aw += *b; + cf |= (aw < *(b--)); + *(a--) = aw; + } +} + + +//------------------------------------- +// a,b < prime +// never with order as base +// +static void bn_modadd (bn_t *a, const bn_t *b) +{ + EC_ASSERT(NULL != a); + EC_ASSERT(NULL != b); + //EC_ASSERT(!bn_ge_prime(a)); + //EC_ASSERT(!bn_ge_prime(b)); + + bn_add(a, b); // P521: can not generate carry (unused MSW bits) + // other curves need to handle this carry + +#ifndef EC_POWER64_RED + if (bn_ge_prime(a)) + bn_sub(a, consts_p()->ec_prime); +#endif +} + + +//------------------------------------- +// never with order as base +static bn_t bn_sub (bn_t *a, const bn_t *b) +{ + bnindex_t i = NWORDS; + bn_t bw, cf = 0; + + EC_ASSERT(NULL != a); + EC_ASSERT(NULL != b); + + a += NWORDS-1; + b += NWORDS-1; + + while (0 < i--) { + if (cf) + cf = (0 == (*a)--); + + bw = *b; + cf |= (*a < *(b--)); + *(a--) -= bw; + } + + return cf; +} + + +//------------------------------------- +// never modular-subtracting with ec_order[], only with ec_prime[] +// therefore, implicit modulus +// +static void bn_modsub (bn_t *a, const bn_t *b) +{ + EC_ASSERT(NULL != a); + EC_ASSERT(NULL != b); + //EC_ASSERT(!bn_ge_prime(a)); + EC_ASSERT(!bn_ge_prime(b)); + + if (bn_sub(a, b)) + bn_add(a, consts_p()->ec_prime); +} + + + +//------------------------------------- +// only rn LS words are touched +// +static void bn_shl_n (bn_t r[NWORDS], unsigned int rn, unsigned int bits) +{ + bn_t cf = 0, cfin; + + EC_DEVASSERT(NULL != r); + EC_ASSERT(rn <= NWORDS); + + r += NWORDS-rn; + + if (bits >= BN_BITS) { // unlikely, most modinv shift is <5 bits + cfin = bits / BN_BITS; // whole words + + memmove(r, r+cfin, (NWORDS-cfin)*sizeof(bn_t)); +#ifndef BN_POWER64_CLR + memset(r+NWORDS-cfin, 0, cfin*sizeof(bn_t)); +#else + bn_clr(r+NWORDS-cfin, cfin); +#endif + + bits %= BN_BITS; + } + + if (bits) { + r += rn-1; + + while (0> (BN_BITS - bits)); + + *r <<= bits; + *r |= cfin; + --r; + } + } +} + + + +static unsigned int bn_bits (const bn_t *a) +{ + unsigned int full = 8*BNBYTES; + bnindex_t i; + bn_t an; + + for (i=0; i 0xff) { + full += 8; + an >>= 8; + } + + while (an) { + ++full; + an >>= 1; + } + + return full; + } + + return 0; +} + + +// XXX route to bnt_msbit +// +#define bn_is_negative(p) (0x1000 & (*(p))) + + +// inv stores S during run +// +static int bn_modinv(bn_t *inv, const bn_t *a, const bn_t *n) +{ + bn_t r[ NWORDS ], s[ NWORDS ], u[ NWORDS ], v[ NWORDS ], + ss[ NWORDS ], vs[ NWORDS ]; // shifted S,V + unsigned int shl, ub, vb; // shift amount; bitcount + bn_t *pr = r, *ps = s, *pu = u, *pv = v, *pt; + + EC_ASSERT(NULL != inv); + EC_ASSERT(NULL != a); + EC_ASSERT(NULL != n); + EC_ASSERT(bn_cmp(a,n) < 0); + EC_ASSERT(!bn_is_zero(a,0)); + + // [1, a] + // [0, n] + + bn_clear(r); + bn_clear(s); + BN_LSW(s) = 1; + + BN_COPY(u, n); + BN_COPY(v, a); + +// bn_print("U ", u); +// bn_print("V ", v); + // ub = bn_bits(u); + ub = EC_PRIMEBITS; // P521: only ec_prime or ec_order possible + vb = bn_bits(v); +// printf("%d,%d\n", (int) ub, (int) vb); + + while (1 < vb) { + EC_ASSERT(ub >= vb); + shl = ub-vb; +// printf("< %d\n", shl); + + BN_COPY(vs, pv); + BN_COPY(ss, ps); + if (shl) { + bn_shl_n(vs, NWORDS, shl); + bn_shl_n(ss, NWORDS, shl); + } + + if (bn_is_negative(pv) == bn_is_negative(pu)) { + bn_sub(pu, vs); + bn_sub(pr, ss); + } else { + bn_add(pu, vs); + bn_add(pr, ss); + } + +// bn_print("u ", pu); +// bn_print("r ", pr); + if (bn_is_negative(pu)) { + bn_clear(ss); + bn_sub(ss, pu); + ub = bn_bits(ss); + } else { + ub = bn_bits(pu); + } + + if (ub < vb) { + shl = ub; // shl,ss used as swap-scratch + ub = vb; + vb = shl; + + pt = pu; + pu = pv; + pv = pt; + + pt = ps; + ps = pr; + pr = pt; + } +// printf("\n"); + } + + if (bn_is_negative(pv)) { + BN_COPY(ss, ps); + bn_clear(ps); + bn_sub(ps, ss); + } + + if (bn_is_negative(ps)) + bn_add(ps, n); + + if (bn_cmp(ps, n) >= 0) + bn_sub(ps, n); + BN_COPY(inv, ps); + + return 1; +} + + +//------------------------------------- +#if defined(__BIG_ENDIAN) + + +static void bn_read_pt(bn_t *r, const unsigned char *data) +{ + EC_ASSERT(NULL != r); + EC_ASSERT(NULL != data); + + r[0] = 0; + memmove(((unsigned char *) r) +BNBYTES-EC_PRIMEBYTES, + data, EC_PRIMEBYTES); +} + + +// P521: hash does not have unused MS words +// +static void bn_read_hash(bn_t *r, const unsigned char *data) +{ + EC_ASSERT(NULL != r); + EC_ASSERT(NULL != data); + + r[0] = 0; + memmove(((unsigned char *) r) +BNBYTES-EC_HASHBYTES, + data, EC_HASHBYTES); +} + + +#else + +static void bn_read(bn_t *r, const unsigned char *data, size_t dlen) +{ + bnindex_t i, whole = dlen / sizeof(bn_t), + rem = dlen % sizeof(bn_t); + bn_t acc = 0; + + EC_ASSERT(NULL != r); + EC_ASSERT(NULL != data); + EC_ASSERT(dlen <= EC_PRIMEBYTES); + + acc = whole + (!!rem); + if (acc < NWORDS) { // unused MS words + acc = NWORDS - acc; +#ifndef BN_POWER64_CLR + memset(r, 0, acc*sizeof(bn_t)); +#else + bn_clr(r, acc); +#endif + r += acc; + } + + acc = 0; + if (rem) { + ++whole; + } else { + rem = sizeof(bn_t); + } + + while (0 < whole--) { + for (i=0; iec_prime); + bn_modmul_prime(x, zinv); +#ifdef EC_POWER64_RED + bn_modred_slow(x); +#endif +} + + +// returns 1 if result is at infinity, 0 otherwise +// +static int ec_add (bn_t *x1, bn_t *y1, bn_t *z1, + const bn_t *x2, const bn_t *y2, const bn_t *z2) +{ + bn_t a[ NWORDS ], b[ NWORDS ], c[ NWORDS ], + bs[ NWORDS ], // B^2 + t1[ NWORDS ], t2[ NWORDS ]; // XXX minimize these + int inf1, inf2; + + EC_ASSERT(NULL != x1); + EC_ASSERT(NULL != y1); + EC_ASSERT(NULL != z1); + EC_ASSERT(NULL != x2); + EC_ASSERT(NULL != y2); + EC_ASSERT(NULL != z2); + EC_ASSERT(!bn_ge_prime(x1)); + EC_ASSERT(!bn_ge_prime(y1)); + EC_ASSERT(!bn_ge_prime(z1)); + EC_ASSERT(!bn_ge_prime(x2)); + EC_ASSERT(!bn_ge_prime(y2)); + EC_ASSERT(!bn_ge_prime(z2)); + + inf1 = ec_is_infinity(x1, y1, z1); + inf2 = ec_is_infinity(x2, y2, z2); + + if (inf2) + return inf1; + + if (inf1) { + BN_COPY(x1, x2); + BN_COPY(y1, y2); + BN_COPY(z1, z2); + return 0; // (x1,y1,z1) not infinity (checked above) + } + + if (!bn_cmp(x1, x2) && !bn_cmp(y1, y2)) + return ec_double(x1, y1, z1); + +#ifdef EC_POWER64_ALG + BN_COPY(t1, y1); + bn_modmul_prime(t1, z2); // t1 = y1 * z2 + BN_COPY(a, y2); + bn_modmul_prime(a, z1); // A = y2 * z1 - y1 * z2 +#ifdef EC_POWER64_RED + bn_modred_slow(t1); +#endif + bn_modsub(a, t1); + + bn_modmul_prime(x1, z2); // x1 := x1 * z2 orig x1 no longer used + BN_COPY(b, x2); + bn_modmul_prime(b, z1); +#ifdef EC_POWER64_RED + bn_modred_slow(x1); +#endif + bn_modsub(b, x1); // B = x2 * z1 - x1 * z2 + + BN_COPY(bs, b); + bn_modsqr_prime(bs); // B^2 + + BN_COPY(c, a); + bn_modsqr_prime(c); + bn_modmul_prime(z1, z2); // z1 = z1 * z2 + bn_modmul_prime(c, z1); // c = A^2 * z1 * z2 + + bn_modmul_prime(x1, bs); // x1 = B^2 * x1 * z2 + BN_COPY(t2, b); + bn_modmul_prime(t2, bs); // t2 = B^3 +#ifdef EC_POWER64_RED + bn_modred_slow(t2); + bn_modred_slow(x1); +#endif + bn_modsub(c, t2); + bn_modsub(c, x1); // C = A^2 * z1 * z2 - B^3 + bn_modsub(c, x1); // - 2 B^2 * x1 * z1 + + bn_modmul_prime(z1, t2); // z1 * z2 * B^3 +#ifdef EC_POWER64_RED + bn_modred_slow(z1); + bn_modred_slow(c); +#endif + + bn_modmul_prime(t1, t2); // (B^3 * y1 * z2) + // A(B 2 X1 Z2 ? C) + bn_modsub(x1, c); + bn_modmul_prime(x1, a); // A * (B^2 * x1 * z2 - C) +#ifdef EC_POWER64_RED + bn_modred_slow(x1); + bn_modred_slow(t1); +#endif + bn_modsub(x1, t1); // Y = A * (B^2 * x1 * z2 - C) - (B^3 * y1 * z2) + BN_COPY(y1, x1); + + BN_COPY(x1, b); + bn_modmul_prime(x1, c); // X = B * C +#ifdef EC_POWER64_RED + bn_modred_slow(x1); +#endif + +#else // !EC_POWER64_ALG + BN_COPY(t1, y1); + bn_modmul_prime(t1, z2); // t1 = y1 * z2 + BN_COPY(a, y2); + bn_modmul_prime(a, z1); // A = y2 * z1 - y1 * z2 + bn_modsub(a, t1); + + bn_modmul_prime(x1, z2); // x1 := x1 * z2 orig x1 no longer used + BN_COPY(b, x2); + bn_modmul_prime(b, z1); + bn_modsub(b, x1); // B = x2 * z1 - x1 * z2 + + BN_COPY(bs, b); + bn_modmul_prime(bs, bs); // B^2 + + BN_COPY(c, a); + bn_modmul_prime(c, c); + bn_modmul_prime(c, z1); + bn_modmul_prime(c, z2); + + BN_COPY(t2, b); + bn_modadd(t2, x1); + bn_modadd(t2, x1); + bn_modmul_prime(t2, bs); + bn_modsub(c, t2); // C = A^2 * z1 * z2 - B^3 + // - 2 B^2 * x1 * z1 + + bn_modmul_prime(z1, z2); + bn_modmul_prime(z1, b); + bn_modmul_prime(z1, bs); // z1 * z2 * B^3 + + bn_modmul_prime(t1, b); + bn_modmul_prime(t1, bs); // (B^3 * y1 * z2) + // A(B 2 X1 Z2 ? C) + bn_modmul_prime(x1, bs); // (B^2 * x1 * z2) + bn_modsub(x1, c); + bn_modmul_prime(x1, a); // A * (B^2 * x1 * z2 - C) + bn_modsub(x1, t1); + BN_COPY(y1, x1); // Y = + + BN_COPY(x1, b); + bn_modmul_prime(x1, c); // X = B * C +#endif + + return 0; +} + + + + +//---------------------------------------------------------------------------- +// (x,y,z) in projective coordinates +// P521: curve has a==-3 +// +// return 1 if point in infinity +// +static int ec_double (bn_t *x, bn_t *y, bn_t *z) +{ + bn_t a[ NWORDS ], b[ NWORDS ], c[ NWORDS ], d[ NWORDS ], t[ NWORDS ]; + + EC_ASSERT(NULL != x); + EC_ASSERT(NULL != y); + EC_ASSERT(NULL != z); + EC_ASSERT(!bn_ge_prime(x)); + EC_ASSERT(!bn_ge_prime(y)); + EC_ASSERT(!bn_ge_prime(z)); + +#ifdef EC_POWER64_ALG + BN_COPY(a, x); + BN_COPY(d, x); + + bn_modadd(a, z); + bn_modsub(d, z); + bn_modmul_prime(a, d); // x^2 - z^2 + BN_COPY(d, a); + bn_modadd(a, a); + bn_modadd(a, d); // A = 3 * (x^2 - z^2) + // P521: generally, A = 3 * x^2 - a * z^2 + + BN_COPY(b, z); + bn_modmul_prime(b, y); // B = y * z + + BN_COPY(c, x); + bn_modmul_prime(y, b); // y = y * B + bn_modmul_prime(c, y); // C = x * y * B + + BN_COPY(z, b); + bn_modsqr_prime(z); + bn_modmul_prime(z, b); + bn_modadd(z, z); + bn_modadd(z, z); + bn_modadd(z, z); // Z = 8 * B^3 +#ifdef EC_POWER64_RED + bn_modred_slow(z); +#endif + + BN_COPY(t, c); + bn_modadd(t, t); + bn_modadd(t, t); + bn_modadd(t, t); + BN_COPY(d, a); + bn_modsqr_prime(d); +#ifdef EC_POWER64_RED + bn_modred_slow(t); +#endif + bn_modsub(d, t); // D = A^2 - 8*C + + BN_COPY(x, b); + bn_modmul_prime(x, d); + bn_modadd(x, x); // X = 2 * B * D +#ifdef EC_POWER64_RED + bn_modred_slow(x); + bn_modred_slow(d); +#endif + + bn_modadd(c, c); + bn_modadd(c, c); + bn_modsub(c, d); + bn_modmul_prime(a, c); // (A * (4*C - D)) + + bn_modsqr_prime(y); // (y * B)^2 + bn_modadd(y, y); + bn_modadd(y, y); + bn_modadd(y, y); // (8 * y^2 * B^2) +#ifdef EC_POWER64_RED + bn_modred_slow(a); + bn_modred_slow(y); +#endif + bn_modsub(a, y); + BN_COPY(y, a); // Y = A * (4*C - D) - 8 * y^2 * B^2 + +#else // !EC_POWER64_ALG + BN_COPY(a, x); + BN_COPY(d, z); + + bn_modmul_prime(a, x); + bn_modmul_prime(d, z); + bn_modsub(a, d); + BN_COPY(d, a); + bn_modadd(a, a); + bn_modadd(a, d); // A = 3 * (x^2 - z^2) + // P521: generally, A = 3 * x^2 - a * z^2 + + BN_COPY(b, z); + bn_modmul_prime(b, y); // B = y * z + + BN_COPY(c, y); + bn_modmul_prime(c, b); + bn_modmul_prime(c, x); // C = x * y * B + + BN_COPY(z, b); + bn_modmul_prime(z, b); + bn_modmul_prime(z, b); + bn_modadd(z, z); + bn_modadd(z, z); + bn_modadd(z, z); // Z = 8 * B^3 + + BN_COPY(t, c); + bn_modadd(t, t); + bn_modadd(t, t); + bn_modadd(t, t); + BN_COPY(d, a); + bn_modmul_prime(d, a); + bn_modsub(d, t); // D = A^2 - 8*C + + BN_COPY(x, b); + bn_modmul_prime(x, d); + bn_modadd(x, x); // X = 2 * B * D + + bn_modadd(c, c); + bn_modadd(c, c); + bn_modsub(c, d); + bn_modmul_prime(a, c); // (A * (4*C - D)) + + bn_modmul_prime(y, b); + bn_modmul_prime(y, y); + bn_modadd(y, y); + bn_modadd(y, y); + bn_modadd(y, y); // (8 * y^2 * B^2) + bn_modsub(a, y); + BN_COPY(y, a); // Y = A * (4*C - D) - 8 * y^2 * B^2 +#endif + + return 0; +} + + + +//------------------------------------- +// (x,y) in affine coordinates; z is output only +// returns (x,y,z) in projective coordinates +// +// we roll (x,y), updating (qx,qy) if necessary +// finally, (x,y) := (qx,qy) +// +// LIMIT: processes up to EC_PRIMEBITS in coefficient +// z and k must not overlap +// +static int ec_multiply (bn_t *x, bn_t *y, bn_t *z, const bn_t *k) +{ + bn_t px[ NWORDS ], py[ NWORDS ], pz[ NWORDS ]; + unsigned int i; + bn_t mask = 1; + + EC_ASSERT(NULL != x); + EC_ASSERT(NULL != y); + EC_ASSERT(NULL != k); + EC_ASSERT(!bn_ge_prime(x)); + EC_ASSERT(!bn_ge_prime(y)); + + i=bn_bits(k); + k += NWORDS-1; + + BN_COPY(px, x); + BN_COPY(py, y); + bn_clear(x); + bn_clear(y); + + bn_clear(z); + BN_LSW(z) = 1; // (x,y) -> (x, y, 1) in projective coordinates + BN_COPY(pz, z); // (px,py) -> (px,py,1) + + BN_DUMP(i,x); + BN_DUMP(i,y); + BN_DUMP(i,z); + BN_DUMP(i,px); + BN_DUMP(i,py); + BN_DUMP(i,pz); + while (0 < i--) { + if (mask & *k) + ec_add(x, y, z, px, py, pz); + + if (0 < i) + ec_double(px, py, pz); + + BN_DUMP(i,x); + BN_DUMP(i,y); + BN_DUMP(i,z); + BN_DUMP(i,px); + BN_DUMP(i,py); + BN_DUMP(i,pz); + mask <<= 1; + if (!mask) { + --k; + mask = 1; + } + } + BN_EXIT(); + + return 0; +} + + +//===================================================== public function ==== +asm(".globl .L.ec_verify"); +int ec_verify (const unsigned char *publicpt, /* 2*EC_COORDBYTES */ + const unsigned char *hash, /* EC_HASHBYTES */ + const unsigned char *signature) /* 2*EC_COORDBYTES */ +{ + bn_t r[ NWORDS ], s[ NWORDS ], e[ NWORDS ], + px[ NWORDS ], py[ NWORDS ], pz[ NWORDS ], + u1[ NWORDS ], u2[ NWORDS ]; + + if ((NULL == publicpt) || (NULL == signature) || (NULL == hash)) + return -1; + + bn_read_pt (r, signature); + bn_read_pt (s, signature +EC_COORDBYTES); + bn_read_hash(e, hash); + bn_read_pt (px, publicpt); + bn_read_pt (py, publicpt +EC_COORDBYTES); + + if (bn_ge_order(r) || bn_ge_order(s) || + bn_is_zero(s,0) || bn_is_zero(r,0)) + return 0; // assume user messed with signature + + if (bn_ge_prime(px) || bn_ge_prime(py) || + bn_is_zero(px,0) || bn_is_zero(py,0)) + return -1; // admin fault; should not happen + + bn_modinv(u1, s, consts_p()->ec_order); // s no longer needed (NLN) + BN_COPY(u2, r); + bn_modmul_order(u2, u1); + bn_modmul_order(u1, e); // e NLN + + // reuse (e,s) for base multiplication + BN_COPY(e, consts_p()->prime_px); // (e,s) <- (base point) + BN_COPY(s, consts_p()->prime_py); + + ec_multiply(px, py, pz, u2); // (px,py,pz) = u2 * (px,py); u2 NLN + ec_multiply(e, s, u2, u1); // (s, e, u2) = u1 * (gx,gy); u1 NLN + + if (ec_add(px, py, pz, e, s, u2)) // u1 * base + u2 * public + return 0; // reached infinity (SNH with sig) + + ec_projective2affine(px, pz); + + if (bn_ge_order(px)) + bn_sub(px, consts_p()->ec_order); // px mod order + + return (! bn_cmp(r, px)); +} + diff --git a/src/securerom/hw_utils.C b/src/securerom/hw_utils.C new file mode 100644 index 00000000000..19d4ee94729 --- /dev/null +++ b/src/securerom/hw_utils.C @@ -0,0 +1,222 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/securerom/hw_utils.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/**************************************************************************** + * + ****************************************************************************/ +#include +#include + +/****************************************************************************/ + +#ifdef EMULATE_HW + +#include +#include +#include +#include +#include /* uint_fast8_t, uintN_t */ +#include +hw_settings HW; + +/****************************************************************************/ +void HW_Init (void) { + /* Open the file that will be used to fill the memory contents of the mmap */ + HW.mfd = open ("/dev/zero", O_RDWR, 0); + if (HW.mfd < 0) { + printf ("HW_Init: can't create memory file"); + exit(1); + } + /* Allocate Memory */ +#ifdef HOST_64 + HW.data = (uint8_t*) mmap64 (0, TOTAL_TEST_MEMORY, + PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, HW.mfd, 0); +#else + HW.data = (uint8_t*) mmap (0, TOTAL_TEST_MEMORY, + PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, HW.mfd, 0); +#endif + if ((uint32_t) HW.data == -1) { + printf ("Unable to allocate HW Memory of size %d", TOTAL_TEST_MEMORY); + HW_Free(); + exit(1); + } + HW.memory = HW.data+0x1000-((uint32_t)HW.data&0xfff); +} + +/****************************************************************************/ +void HW_Free (void) +{ + close (HW.mfd); +} + +/****************************************************************************/ +void Log (uint64_t code) { + mtspr_SCRATCH2 (code); +} + +/****************************************************************************/ +void Check_Stop (char* msg) { + printf ("CHECK STOP '%s'\n", msg); + printf ("SCRATCH3= 0x%08llX\n", mfspr_SCRATCH3()); + exit(FAIL); +} + +/****************************************************************************/ +void Error_Stop (uint64_t code, char* msg) { + mtspr_SCRATCH3 (ERROR_EVENT|code); + Check_Stop (msg); +} + +/****************************************************************************/ +void assem_DCBI (uint64_t addr) { + addr = physical_addr(addr)&CACHE_MASK; + memset(Convert_Mem_Addr(addr),0xff,CACHE_LINE); // destroys contents in model + } +/****************************************************************************/ +void assem_DCBZ (uint64_t addr) { + addr = physical_addr(addr)&CACHE_MASK; + memset(Convert_Mem_Addr(addr),0,CACHE_LINE); +} +/****************************************************************************/ +void assem_DCBST (uint8_t* addr) {} +/****************************************************************************/ +void assem_ICBI (uint64_t* addr) {} +/****************************************************************************/ +void assem_SYNC (void) {} +/****************************************************************************/ +void assem_ISYNC (void) {} + +/****************************************************************************/ +void mtspr_HRMOR (uint64_t addr) { + HW.HRMOR = addr & HRMOR_MASK; +} + +/****************************************************************************/ +//uint64_t mfspr_HRMOR (void) { +// return HW.HRMOR; +//} + +/****************************************************************************/ + +/****************************************************************************/ +uint64_t getscom_FSP_BAR_value (uint64_t base) { + return HW.FSP_BAR.value; +} + +/****************************************************************************/ +uint64_t getscom_FSP_BAR_mask (uint64_t base) { + return HW.FSP_BAR.mask; +} + +/****************************************************************************/ +void getscom_HW_ECID (uint64_t base, uint8_t* buf) { + memcpy(buf, HW.ECID, ECID_SIZE); +} + +/****************************************************************************/ +void getscom_PIBMEM_HW_Key_Hash (uint64_t base, uint8_t* buf) { + memcpy(buf, HW.PIBMEM_HW_KEY_HASH, SHA512_DIGEST_SIZE); +} + +/****************************************************************************/ +uint8_t* Convert_Mem_Addr (uint64_t addr) { + if (addr >= TEST_SYSTEM_MEMORY) return NULL; + return HW.memory+addr; +} + +/****************************************************************************/ +uint64_t physical_addr (uint64_t addr) { + if (addr & HRMOR_IGNORE) addr = PHYSICAL(addr); + else addr = PHYSICAL(addr) | HW.HRMOR; + return addr; +} + +/****************************************************************************/ +uint64_t Convert_Mem_Offset (uint8_t* addr) { + if (addr < HW.memory) return 0; + return (uint64_t)(uint32_t)(addr-HW.memory); +} + +/****************************************************************************/ +uint16_t GET16(uint16_t data) { +#ifdef __BIG_ENDIAN + return data; +#endif +#ifdef __LITTLE_ENDIAN + return ((data&0x00FF)<<8 + |(data&0xFF00)>>8 + ); +#endif +} + +/****************************************************************************/ +uint32_t GET32 (uint32_t data) { +#ifdef __BIG_ENDIAN + return data; +#endif +#ifdef __LITTLE_ENDIAN + return ((data&0x000000FF)<<24 + |(data&0x0000FF00)<<8 + |(data&0x00FF0000)>>8 + |(data&0xFF000000)>>24 + ); +#endif +} + +/****************************************************************************/ +uint64_t GET64 (uint64_t data) { +#ifdef __BIG_ENDIAN + return data; +#endif +#ifdef __LITTLE_ENDIAN + return ((data&0x00000000000000FFull)<<(7*8) + |(data&0x000000000000FF00ull)<<(5*8) + |(data&0x0000000000FF0000ull)<<(3*8) + |(data&0x00000000FF000000ull)<<(1*8) + |(data&0x000000FF00000000ull)>>(1*8) + |(data&0x0000FF0000000000ull)>>(3*8) + |(data&0x00FF000000000000ull)>>(5*8) + |(data&0xFF00000000000000ull)>>(7*8) + ); +#endif +} + +#else + +void __attribute__((noreturn)) Check_Stop(void) { + //do not use XSCOM as the XSCOM base is not known for sure + + //set AVP_out to (optionally) cause secure checkstop + mtspr(SPRC,SPRC_AVP_out); + mtspr(SPRD,-1LL); + + asm volatile(" li 0,0 \n" + " mtmsr 0 \n" //ensure there is no error handler so it will checkstop instead + " lis 0,-1107 \n" + " stdcix 0,0,0 \n" //store to invalid address + " eieio "); + for(;;) {} +} + +#endif //emulate_hw diff --git a/src/securerom/inttypes.H b/src/securerom/inttypes.H new file mode 100644 index 00000000000..397732961c9 --- /dev/null +++ b/src/securerom/inttypes.H @@ -0,0 +1,41 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/securerom/inttypes.H $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +#define uint_fast8_t uint8_t + +#ifndef BYTE_ORDER +#error "BYTE_ORDER MUST BE DEFINED" +#endif /* #ifndef BYTE_ORDER */ + +#if BYTE_ORDER == LITTLE_ENDIAN +#undef __BIG_ENDIAN +#ifndef __LITTLE_ENDIAN +#define __LITTLE_ENDIAN 4321 +#endif +#else +#undef __LITTLE_ENDIAN +#ifndef __BIG_ENDIAN +#define __BIG_ENDIAN 1234 +#endif +#endif diff --git a/src/securerom/makefile b/src/securerom/makefile new file mode 100644 index 00000000000..4b3a5a3cf37 --- /dev/null +++ b/src/securerom/makefile @@ -0,0 +1,244 @@ +# IBM_PROLOG_BEGIN_TAG +# This is an automatically generated prolog. +# +# $Source: src/securerom/makefile $ +# +# OpenPOWER HostBoot Project +# +# Contributors Listed Below - COPYRIGHT 2016,2017 +# [+] International Business Machines Corp. +# +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. See the License for the specific language governing +# permissions and limitations under the License. +# +# IBM_PROLOG_END_TAG + +bootrom := bootrom +bootrom_bin = $(bootrom).bin +bootrom_dis = $(bootrom).dis +#bootrom_srec = $(bootrom).srec + +bootrom_vhdl = ../vhdl/tpc_secr_rom_pkg.vhdl + +bootrom_nm = $(bootrom).nm + +LDSCRIPT = bootrom.lds + +HOSTTYPE ?= $(shell uname -p) +CELLSIZE ?= 64 + +ifeq ($(HOSTTYPE),powerpc) +CROSS ?= powerpc-ibm-aix6.1.0.0- +ONLY_CC = $(CROSS)gcc -mpowerpc64 -maix64 -Wa,-mANY +ONLY_AS = $(CROSS)as -m$(CELLSIZE) +ONLY_LD = $(CROSS)ld -melf$(CELLSIZE)ppc +OBJCOPY ?= $(CROSS)objcopy +OBJDUMP ?= $(CROSS)objdump +else +CROSS ?= powerpc-linux-gnu- +ONLY_CC = $(CROSS)gcc -m64 -Wa,-mregnames +ONLY_AS = $(CROSS)as -m64 -mregnames +ONLY_LD = $(CROSS)ld -melf64ppc +OBJCOPY ?= $(CROSS)objcopy +OBJDUMP ?= $(CROSS)objdump +endif + + +# Verbose level: +# V=0 means completely silent +# V=1 means brief output +# V=2 means full verbose output +V ?= 2 + +ifeq ($(V),0) +Q := @ +MAKEFLAGS += --silent +MAKE += -s +endif + +ifeq ($(V),1) +MAKEFLAGS += --silent +MAKE += -s +CC = printf "\t[CC]\t$@\n"; $(ONLY_CC) +AS = printf "\t[AS]\t$@\n"; $(ONLY_AS) +LD = printf "\t[LD]\t$@\n"; $(ONLY_LD) +CLEAN = printf "\t[CLEAN]\t%s\n" "$(DIRECTORY)$$dir" +else +CC = $(ONLY_CC) +AS = $(ONLY_AS) +LD = $(ONLY_LD) +CLEAN = echo -n +endif + +# need version >= 1_0_0 +#OPENSSL ?= ~/openssl/openssl-1.0.0/bin/openssl +#SREC_CAT ?= srec_cat + +CPPFLAGS += -DCONFIG_AWAN \ + -I./src/ -I./include/ \ + -DCELLSIZE=$(CELLSIZE) \ + -DBYTE_ORDER=BIG_ENDIAN \ + -g \ + +#CPPFLAGS += -DEC_POWER64_ASM +CPPFLAGS += -DBN_POWER64_MUL +CPPFLAGS += -DBN_POWER64_CMP +CPPFLAGS += -DBN_POWER64_CPY +CPPFLAGS += -DBN_POWER64_CLR +CPPFLAGS += -DEC_POWER64_RED +#CPPFLAGS += -DBN_POWER64_SQR +CPPFLAGS += -DEC_POWER64_ALG +#CPPFLAGS += -DBN_POWER64_DBG +CPPFLAGS += -DSHA512_FIX + +OBJDIR = obj + +ifeq ($(MAMBO),yes) +CPPFLAGS += -DCONFIG_MAMBO +bootrom := bootrom_4mambo +OBJDIR = mambo +endif + +asm_srcs = src/branchtable.S +c_srcs = src/ROM.c src/sha512.c src/ecverify.c +c_srcs += src/memmove.c src/memcmp.c src/hw_utils.c +#c_srcs += src/memset.c src/memcpy.c + +CPPFLAGS += -DCONFIG_SOFTWARE_CRYPTO + +srcs = $(asm_srcs) $(c_srcs) +objs = $(subst src/,$(OBJDIR)/,$(asm_srcs:.S=.o) $(c_srcs:.c=.o)) +deps = $(subst src/,$(OBJDIR)/,$(asm_srcs:.S=.d) $(c_srcs:.c=.d)) + +CFLAGS ?= -W -Os -fno-builtin -ffreestanding -nostdinc -mno-toc \ + -msoft-float -mno-altivec -mabi=no-altivec -Wall -mregnames \ + $(CPPFLAGS) + +ASFLAGS += $(CPPFLAGS) -Wa,-mregnames -D__ASSEMBLER__ + +LDFLAGS = -nostdlib -N + + +default: + $(MAKE) all + $(MAKE) MAMBO=yes bootrom_4mambo.dis bootrom_4mambo.bin + +$(OBJDIR): + @if [ -d $(OBJDIR) ] ; then true; else mkdir -p $(OBJDIR); fi + +all: $(bootrom_dis) $(bootrom_bin) $(bootrom_vhdl) + + +NODEPS = clean distclean binclean +ifeq (0, $(words $(findstring $(MAKECMDGOALS), $(NODEPS)))) +-include $(deps) +endif + + +## This was to create a selfsigned rom code but now it is no longer selfsigned : + +#ec_private_key.pem: +# $(OPENSSL) ecparam -name secp521r1 -genkey -out ec_private_key.pem + +#ec_private_key.pem: ec_private_key.pkcs8 +# $(OPENSSL) pkcs8 -inform DER -nocrypt -in ec_private_key.pkcs8 -out ec_private_key.pem +#ec_private_key.pkcs8: +# ./ecdsasig.x86 -r -g x > ec_private_key.pkcs8 + +#ec_public_key.der: ec_private_key.pem +# $(OPENSSL) ec -in ec_private_key.pem -pubout -outform DER -out ec_public_key.der + +#$(bootrom).stage1: $(objs) $(gen_hdrs) $(prism_hdrs) src/dummy_header.o src/dummy_hash.o +# $(LD) $(LDFLAGS) -o $@ $(objs) src/dummy_header.o src/dummy_hash.o + +#$(bootrom).signed.bin: $(bootrom).stage1 +# $(OBJCOPY) -j .text -j .data -O binary $^ $@ + +#dummy_header.bin: $(bootrom).stage1 +# $(OBJCOPY) -j .image_header -O binary $^ $@ + +#$(bootrom).signed.sig: $(bootrom).signed.bin ec_private_key.pem +# $(OPENSSL) dgst -sign ec_private_key.pem -sha512 $^ > $@ + +#image_header.bin: ec_public_key.der $(bootrom).signed.sig src/dummy_header.o dummy_header.bin +# ./asn1extract_pubkey.pl ec_public_key.der > image_header.bin +# dd bs=132 count=2 if=/dev/zero >> image_header.bin +# ./asn1extract.pl bootrom.signed.sig | xxd -r -p >> image_header.bin +# dd bs=132 count=2 if=/dev/zero >> image_header.bin +# dd bs=1 skip=792 count=88 if=dummy_header.bin >> image_header.bin + +#image_header.o: image_header.bin +# $(OBJCOPY) -I binary -O elf64-powerpc -B powerpc --rename-section .data=.image_header --redefine-sym _binary_image_header_bin_start=rom_image_header image_header.bin image_header.o + +#$(bootrom).stage2: $(objs) $(gen_hdrs) $(prism_hdrs) image_header.o src/dummy_hash.o +# $(LD) $(LDFLAGS) -o $@ $(objs) image_header.o src/dummy_hash.o + +#bootrom.hashed.bin: $(bootrom).stage2 +# $(OBJCOPY) -j .image_hash -j .text -j .data -O binary $^ $@ + +#bootrom.hashed.hash: bootrom.hashed.bin +# $(OPENSSL) dgst -sha512 bootrom.hashed.bin | sed -e "s/.* //" | xxd -r -p > bootrom.hashed.hash + +#rom_hash.o: bootrom.hashed.hash +# $(OBJCOPY) -I binary -O elf64-powerpc -B powerpc \ +# --rename-section .data=.rom_hash \ +# --redefine-sym _binary_bootrom_hashed_hash_start=rom_hash \ +# bootrom.hashed.hash rom_hash.o + +#$(bootrom): $(objs) $(gen_hdrs) $(prism_hdrs) image_header.o rom_hash.o +# $(LD) $(LDFLAGS) -o $@ $(objs) image_header.o rom_hash.o + +$(bootrom): $(objs) $(LDSCRIPT) + $(LD) $(LDFLAGS) -T$(LDSCRIPT) -o $@ $(objs) + +$(bootrom_dis): $(bootrom) + $(OBJDUMP) -j .branchtable -j .text -j .data -j .toc --source $^ > $@ + +#$(bootrom_srec): $(bootrom) +# $(OBJCOPY) --change-addresses -0xff80000 $^ -O srec $@ + +$(bootrom_bin): $(bootrom) + $(OBJCOPY) -j .branchtable -j .text -j .data -j .toc -O binary $^ $@ + +$(bootrom_vhdl): $(bootrom_bin) convVhdl.pl + ./convVhdl.pl $^ > $@ + +$(OBJDIR)/%.o: src/%.S $(OBJDIR)/%.d + $(CC) $(ASFLAGS) -c $< -o $@ + +$(OBJDIR)/%.o: src/%.c $(OBJDIR)/%.d + $(CC) $(CFLAGS) -c $< -o $@ + +$(OBJDIR)/%.d: src/%.S Makefile $(OBJDIR) + $(CC) -MM $(ASFLAGS) $< | sed 's,\(\S*\)\.o[ :]*,$(OBJDIR)/\1.o $(OBJDIR)/\1.d : ,g' > $@ + +$(OBJDIR)/%.d: src/%.c Makefile $(OBJDIR) + $(CC) -MM $(CFLAGS) $< | sed 's,\(\S*\)\.o[ :]*,$(OBJDIR)/\1.o $(OBJDIR)/\1.d : ,g' > $@ + +#ecdsa: src/ecdsa.c src/ecverify.c +# gcc -W -Os -fno-builtin -ffreestanding -nostdinc -msoft-float -mno-altivec -mabi=no-altivec -Wall -I./src/ -I./include/ -o ecdsa src/ecdsa.c src/ecverify.c + +clean: + $(RM) -r *~ obj mambo +# ec_public_key.der \ +# $(bootrom).stage1 $(bootrom).signed.bin $(bootrom).signed.sig dummy_header.bin image_header.bin image_header.o\ +# $(bootrom).stage2 $(bootrom).hashed.bin $(bootrom).hashed.hash rom_hash.o + +distclean: clean + @$(MAKE) binclean + @$(MAKE) MAMBO=yes binclean + +binclean: + $(RM) $(bootrom) $(bootrom_bin) $(bootrom_dis) + +.PHONY: default all clean distclean binclean diff --git a/src/securerom/sha512.C b/src/securerom/sha512.C new file mode 100644 index 00000000000..820ead2648e --- /dev/null +++ b/src/securerom/sha512.C @@ -0,0 +1,482 @@ +/* IBM_PROLOG_BEGIN_TAG */ +/* This is an automatically generated prolog. */ +/* */ +/* $Source: src/securerom/sha512.C $ */ +/* */ +/* OpenPOWER HostBoot Project */ +/* */ +/* Contributors Listed Below - COPYRIGHT 2016,2017 */ +/* [+] International Business Machines Corp. */ +/* */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); */ +/* you may not use this file except in compliance with the License. */ +/* You may obtain a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or */ +/* implied. See the License for the specific language governing */ +/* permissions and limitations under the License. */ +/* */ +/* IBM_PROLOG_END_TAG */ +/******************************************************************** + * SHA-512 BIG-Endian Version + * + *******************************************************************/ + +#include +#include +#include +#include + + +/* Initial hash value HASH(32byte) for SHA-512 */ +const uint64_t sha512_initial_hash_value[8] = { + 0x6a09e667f3bcc908ULL, + 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, + 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, + 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, + 0x5be0cd19137e2179ULL +}; + +/* Hash constant words K for SHA-384 and SHA-512: */ +const uint64_t K512[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + + + +#define SHA512_SHORT_BLOCK_LENGTH (SHA512_BLOCK_LENGTH - 16) + + + +/* + * Macro for incrementally adding the unsigned 64-bit integer n to the + * unsigned 128-bit integer (represented using a two-element array of + * 64-bit words): + */ +#define ADDINC128(w,n) { \ + (w)[0] += (uint64_t)(n); \ + if ((w)[0] < (n)) { \ + (w)[1]++; \ + } \ +} + + + +/* Shift-right (used in SHA-512): */ +#define R(b,x) ((x) >> (b)) + + +/* 64-bit Rotate-right (used in SHA-512): */ +#define S64(b,x) (((x) >> (b)) | ((x) << (64 - (b)))) + + + +/* Two of six logical functions used in SHA-512: */ +#define Ch(x,y,z) (((x) & (y)) ^ ((~(x)) & (z))) +#define Maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) + + + +/* Four of six logical functions used in SHA-512: */ +#define Sigma0_512(x) (S64(28, (x)) ^ S64(34, (x)) ^ S64(39, (x))) +#define Sigma1_512(x) (S64(14, (x)) ^ S64(18, (x)) ^ S64(41, (x))) +#define sigma0_512(x) (S64( 1, (x)) ^ S64( 8, (x)) ^ R( 7, (x))) +#define sigma1_512(x) (S64(19, (x)) ^ S64(61, (x)) ^ R( 6, (x))) + +static void SHA512_Last(SHA512_CTX*); +static void SHA512_Transform(SHA512_CTX*, const uint64_t *); + +/* + * Constant used by SHA256/384/512_End() functions for converting the + * digest to a readable hexadecimal character string: + */ + +static inline void bcopy(const void * SRC, void* DST, size_t length){ + unsigned char * source = (unsigned char *) SRC; + unsigned char * destination = (unsigned char *) DST; + for( ; length ; length--){ + *destination++ = *source++; + } +} +static inline void bzero(void * DST, size_t length){ + unsigned char * destination = (unsigned char *) DST; + for( ; length ; length--){ + *destination++=0x00; + } +} + +// unused: +//static inline int tstrlen(const void * SRC){ +// unsigned char * source = (unsigned char *) SRC; +// int length=0; +// while(source[length]!=0x00){ +// length++; +// } +// return length; +//} + + +/*** SHA-512: *********************************************************/ +asm(".globl .L.SHA512_Init"); +void SHA512_Init(SHA512_CTX* context) { + if (context == (SHA512_CTX*)0) { + return; + } + + uint64_t* sha512_initial_hash_value_p; + #ifdef EMULATE_HW + sha512_initial_hash_value_p = sha512_initial_hash_value; + #else + //selftest_p = &selftest; //this line would introduce a absolute address in the toc + asm volatile("li %0,(__toc_start)@l ### %0 := base+0x8000 \n\t" // because li does not work + "sub %0,r2,%0 \n\t" // because subi does not work + "addi %0,%0,(sha512_initial_hash_value-0x8000)@l" : "=r" (sha512_initial_hash_value_p) ); + #endif + + bcopy(sha512_initial_hash_value_p, context->state, SHA512_DIGEST_LENGTH); + bzero(context->buffer, SHA512_BLOCK_LENGTH); + context->bitcount[0] = context->bitcount[1] = 0; +} + + +static void SHA512_Transform(SHA512_CTX* context, const uint64_t* data) { + uint64_t a, b, c, d, e, f, g, h, s0, s1; + uint64_t T1, T2, *W512 = (uint64_t*)context->buffer; + int j; + + uint64_t* K512_p; + #ifdef EMULATE_HW + K512_p = K512; + #else + //selftest_p = &selftest; //this line would introduce a absolute address in the toc + asm volatile("li %0,(__toc_start)@l ### %0 := base+0x8000 \n\t" // because li does not work + "sub %0,r2,%0 \n\t" // because subi does not work + "addi %0,%0,(K512-0x8000)@l" : "=r" (K512_p) ); + #endif + + /* Initialize registers with the prev. intermediate value */ + a = context->state[0]; + b = context->state[1]; + c = context->state[2]; + d = context->state[3]; + e = context->state[4]; + f = context->state[5]; + g = context->state[6]; + h = context->state[7]; + + j = 0; + do { + /* Apply the SHA-512 compression function to update a..h with copy */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512_p[j] + (W512[j] = *data++); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 16); + + do { + /* Part of the message block expansion: */ + s0 = W512[(j+1)&0x0f]; + s0 = sigma0_512(s0); + s1 = W512[(j+14)&0x0f]; + s1 = sigma1_512(s1); + + /* Apply the SHA-512 compression function to update a..h */ + T1 = h + Sigma1_512(e) + Ch(e, f, g) + K512_p[j] + + (W512[j&0x0f] += s1 + W512[(j+9)&0x0f] + s0); + T2 = Sigma0_512(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + + j++; + } while (j < 80); + + /* Compute the current intermediate hash value */ + context->state[0] += a; + context->state[1] += b; + context->state[2] += c; + context->state[3] += d; + context->state[4] += e; + context->state[5] += f; + context->state[6] += g; + context->state[7] += h; + + /* Clean up */ + a = b = c = d = e = f = g = h = T1 = T2 = 0; +} + + +asm(".globl .L.SHA512_Update"); +void SHA512_Update(SHA512_CTX* context, const sha2_byte *data, size_t len) { + unsigned int freespace, usedspace; + + if (len == 0) { + /* Calling with no data is valid - we do nothing */ + return; + } + + /* Sanity check: */ + //assert(context != (SHA512_CTX*)0 && data != (sha2_byte*)0); + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; + if (usedspace > 0) { + /* Calculate how much free space is available in the buffer */ + freespace = SHA512_BLOCK_LENGTH - usedspace; + + if (len >= freespace) { + /* Fill the buffer completely and process it */ + bcopy(data, &context->buffer[usedspace], freespace); + ADDINC128(context->bitcount, freespace << 3); + len -= freespace; + data += freespace; + SHA512_Transform(context, (uint64_t*)context->buffer); + } else { + /* The buffer is not yet full */ + bcopy(data, &context->buffer[usedspace], len); + ADDINC128(context->bitcount, len << 3); + /* Clean up: */ + usedspace = freespace = 0; + return; + } + } + while (len >= SHA512_BLOCK_LENGTH) { + /* Process as many complete blocks as we can */ + SHA512_Transform(context, (const uint64_t*)data); + ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3); + len -= SHA512_BLOCK_LENGTH; + data += SHA512_BLOCK_LENGTH; + } + if (len > 0) { + /* There's left-overs, so save 'em */ + bcopy(data, context->buffer, len); + ADDINC128(context->bitcount, len << 3); + } + /* Clean up: */ + usedspace = freespace = 0; +} + +static void SHA512_Last(SHA512_CTX* context) { + unsigned int usedspace; + + usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH; + if (usedspace > 0) { + /* Begin padding with a 1 bit: */ + context->buffer[usedspace++] = 0x80; + +#if SHA512_FIX + if (usedspace < SHA512_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + bzero(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); + } else if (usedspace > SHA512_SHORT_BLOCK_LENGTH) { + if (usedspace < SHA512_BLOCK_LENGTH) { + bzero(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA512_Transform(context, (uint64_t*)context->buffer); + + /* And set-up for the last transform: */ + bzero(context->buffer, SHA512_SHORT_BLOCK_LENGTH); + } +#else + if (usedspace < SHA512_SHORT_BLOCK_LENGTH) { + /* Set-up for the last transform: */ + bzero(&context->buffer[usedspace], SHA512_SHORT_BLOCK_LENGTH - usedspace); + } else { + if (usedspace < SHA512_BLOCK_LENGTH) { + bzero(&context->buffer[usedspace], SHA512_BLOCK_LENGTH - usedspace); + } + /* Do second-to-last transform: */ + SHA512_Transform(context, (uint64_t*)context->buffer); + + /* And set-up for the last transform: */ + bzero(context->buffer, SHA512_BLOCK_LENGTH - 2); + } +#endif + } else { + /* Prepare for final transform: */ + bzero(context->buffer, SHA512_SHORT_BLOCK_LENGTH); + + /* Begin padding with a 1 bit: */ + *context->buffer = 0x80; + } + /* Store the length of input data (in bits): */ + *(uint64_t*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH] = context->bitcount[1]; + *(uint64_t*)&context->buffer[SHA512_SHORT_BLOCK_LENGTH+8] = context->bitcount[0]; + + /* Final transform: */ + SHA512_Transform(context, (uint64_t*)context->buffer); +} + +asm(".globl .L.SHA512_Final"); +void SHA512_Final(SHA512_CTX* context, sha2_hash_t *result) { + /* Sanity check: */ + //assert(context != (SHA512_CTX*)0); + + /* If no digest buffer is passed, we don't bother doing this: */ + SHA512_Last(context); + + /* Save the hash data for output: */ + bcopy(context->state, result, SHA512_DIGEST_LENGTH); + + /* Zero out state data */ + bzero(context, sizeof(context)); +} + +asm(".globl .L.SHA512_Hash"); +void SHA512_Hash(const sha2_byte* data, size_t len, sha2_hash_t *result) { + SHA512_CTX context; + + SHA512_Init(&context); + SHA512_Update(&context, data, len); + SHA512_Final(&context, result); +} + +/* +int main( void ){ + int i; + uint64_t hash[8] = {}; + const sha2_byte text[]={"The quick brown fox jumps over the lazy dog"}; + + printf("SHA512 \"%s\"\n",text); + SHA512( text, tstrlen(text), hash ); + for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { + printf("%02x", hash[i]); + if( (i&3) ==3) printf(" "); + if( (i&31) ==31) printf("\n"); + } + + const sha2_byte text2[]={""}; + printf("SHA512 \"%s\"\n",text2); + SHA512( text2, tstrlen(text2), hash ); + for (i = 0; i < SHA512_DIGEST_LENGTH; i++) { + printf("%02x", hash[i]); + if( (i&3) ==3) printf(" "); + if( (i&31) ==31) printf("\n"); + } + +} +*/ + +#if INCLUDE_SHA_TESTS +/****************************************************************************/ +static uint8_t SHA512_Input[] = "abc"; +static uint64_t SHA512_Result[] = { + 0xddaf35a193617abaull, 0xcc417349ae204131ull, 0x12e6fa4e89a97ea2ull, 0x0a9eeee64b55d39aull, + 0x2192992a274fc1a8ull, 0x36ba3c23a3feebbdull, 0x454d4423643ce80eull, 0x2a9ac94fa54ca49full, +}; +static uint8_t SHA512_Input2[] = + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn" + "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu"; +static uint64_t SHA512_Result2[] = { + 0x8e959b75dae313daull, 0x8cf4f72814fc143full, 0x8f7779c6eb9f7fa1ull, 0x7299aeadb6889018ull, + 0x501d289e4900f7e4ull, 0x331b99dec4b5433aull, 0xc7d329eeb6dd2654ull, 0x5e96e55b874be909ull, +}; +#include +/****************************************************************************/ +void SHA512_Test (void) +{ + SHA512 sha; + SHA512_Init (&sha); + SHA512_Update (&sha, SHA512_Input, 3); + SHA512_Finish (&sha, NULL); + if (memcmp((uint8_t*)sha.H, (uint8_t*)SHA512_Result, SHA512_DIGEST_SIZE)) { + printf ("SHA512 Test 1 FAILED with bad digest (\n"); + printf ("%016llx %016llx %016llx %016llx\n",sha.H[0],sha.H[1],sha.H[2],sha.H[3]); + printf ("%016llx %016llx %016llx %016llx\n",sha.H[4],sha.H[5],sha.H[6],sha.H[7]); + printf (")\n"); + } + else { + printf ("SHA512 Test 1 Complete\n"); + } + SHA512_Init (&sha); + SHA512_Update (&sha, SHA512_Input2, 112); + SHA512_Finish (&sha, NULL); + if (memcmp((uint8_t*)sha.H, (uint8_t*)SHA512_Result2, SHA512_DIGEST_SIZE)) { + printf ("SHA512 Test 2 FAILED with bad digest (\n"); + printf ("%016llx %016llx %016llx %016llx\n",sha.H[0],sha.H[1],sha.H[2],sha.H[3]); + printf ("%016llx %016llx %016llx %016llx\n",sha.H[4],sha.H[5],sha.H[6],sha.H[7]); + printf (")\n"); + } + else { + printf ("SHA512 Test 2 Complete\n"); + } + SHA512_Hash (&sha, (uint8_t*)&selftest.ec, sizeof(selftest.ec), NULL); + sha.H[0] = BE2HO_8(sha.H[0]); + sha.H[1] = BE2HO_8(sha.H[1]); + sha.H[2] = BE2HO_8(sha.H[2]); + sha.H[3] = BE2HO_8(sha.H[3]); + sha.H[4] = BE2HO_8(sha.H[4]); + sha.H[5] = BE2HO_8(sha.H[5]); + sha.H[6] = BE2HO_8(sha.H[6]); + sha.H[7] = BE2HO_8(sha.H[7]); + if (memcmp((uint8_t*)sha.H, selftest.sha.hash, SHA512_DIGEST_SIZE)) { + printf ("SHA512 Test 3 FAILED with bad digest (\n"); + printf ("%016llx %016llx %016llx %016llx\n",sha.H[0],sha.H[1],sha.H[2],sha.H[3]); + printf ("%016llx %016llx %016llx %016llx\n",sha.H[4],sha.H[5],sha.H[6],sha.H[7]); + printf (")\n"); + } + else { + printf ("SHA512 Test 3 Complete\n"); + } +} +#endif