diff options
author | Yossi Mansharoff <yossim@codeaurora.org> | 2016-09-04 12:15:22 +0300 |
---|---|---|
committer | Nicolas Dechesne <nicolas.dechesne@linaro.org> | 2016-11-16 14:17:47 +0100 |
commit | 0ae7c9542b61df60ff5ed537489fd4d3f4e73c09 (patch) | |
tree | 8a966d246866ed53858bb21c34eb8f92017a2195 |
LK simple sign tool to work in non secure boot
Imported in git from
https://source.codeaurora.org/patches/quic/imm/PATCH_1694964_410c_signlk.tar.gz
Signed-off-by: Yossi Mansharoff <yossim@codeaurora.org>
Change-Id: Ia8823b78c4d9bbe901e6807d4ff03a29c1e496db
Signed-off-by: Nicolas Dechesne <nicolas.dechesne@linaro.org>
-rwxr-xr-x | LICENSE | 26 | ||||
-rwxr-xr-x | signer/Makefile | 26 | ||||
-rwxr-xr-x | signer/signlk.cpp | 271 | ||||
-rwxr-xr-x | signlk.sh | 134 |
4 files changed, 457 insertions, 0 deletions
@@ -0,0 +1,26 @@ +Copyright (c) 2016, The Linux Foundation. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of The Linux Foundation nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/signer/Makefile b/signer/Makefile new file mode 100755 index 0000000..ebf5f4e --- /dev/null +++ b/signer/Makefile @@ -0,0 +1,26 @@ +CXX=g++ +cur-dir := $(mfile_path) +ELFIODIR=${cur-dir}/ELFIO/elfio/ +SOURCES=${cur-dir}/signlk.cpp +CPPFLAGS=-c -Wall -std=c++0x -I$(cur-dir)/ELFIO/ +INCLUDES=$(ELFIODIR)elfio.hpp $(ELFIODIR)elfio_header.hpp \ + $(ELFIODIR)elfio_note.hpp $(ELFIODIR)elfio_section.hpp \ + $(ELFIODIR)elfio_segment.hpp $(ELFIODIR)elfio_strings.hpp \ + $(ELFIODIR)elfio_symbols.hpp $(ELFIODIR)elfio_utils.hpp \ + $(ELFIODIR)elf_types.hpp +OBJECTS=$(SOURCES:.cpp=.o) +EXECUTABLE=${cur-dir}/signlk + +all: $(SOURCES) $(EXECUTABLE) + +$(EXECUTABLE): $(OBJECTS) + $(CXX) $(LDFLAGS) $(OBJECTS) -o $@ + +.cpp.o: + $(CXX) $(CPPFLAGS) $< -o $@ + +test: $(EXECUTABLE) + ./$(EXECUTABLE) + +clean: + rm $(OBJECTS) $(EXECUTABLE) diff --git a/signer/signlk.cpp b/signer/signlk.cpp new file mode 100755 index 0000000..77fa639 --- /dev/null +++ b/signer/signlk.cpp @@ -0,0 +1,271 @@ +/******************************************************************************/ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. */ +/* */ +/* Redistribution and use in source and binary forms, with or without */ +/* modification, are permitted provided that the following conditions are */ +/* met: */ +/* * Redistributions of source code must retain the above copyright */ +/* notice, this list of conditions and the following disclaimer. */ +/* * Redistributions in binary form must reproduce the above */ +/* copyright notice, this list of conditions and the following */ +/* disclaimer in the documentation and/or other materials provided */ +/* with the distribution. */ +/* * Neither the name of The Linux Foundation nor the names of its */ +/* contributors may be used to endorse or promote products derived */ +/* from this software without specific prior written permission. */ +/* */ +/* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED */ +/* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT */ +/* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS */ +/* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR */ +/* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF */ +/* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR */ +/* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, */ +/* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE */ +/* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN */ +/* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +/******************************************************************************/ + + +#include <iostream> +#include <elfio/elfio.hpp> + +using namespace ELFIO; + +/* struct to store hash segment header */ +typedef struct +{ + unsigned int header_vsn_num; /* Header version number. */ + unsigned int image_id; /* Identifies the type of image this header */ + unsigned int image_src; /* Location of image in flash */ + unsigned int image_dest_ptr; /* Pointer to location to store image in RAM. */ + unsigned int image_size; /* Size of complete image in bytes */ + unsigned int code_size; /* Size of code region of image in bytes */ + unsigned int signature_ptr; /* Pointer to images attestation signature */ + unsigned int signature_size; /* Size of the attestation signature in bytes */ + unsigned int cert_chain_ptr; /* Pointer to the chain of attestation + certificates associated with the image. */ + unsigned int cert_chain_size; /* Size of the attestation chain in bytes */ + +} mi_boot_image_header_type; + +#define HASH_CODE_SIZE 0x80 +#define SIGNATURE_SIZE 0x100 +#define CERT_CHAIN_SIZE 0x1800 +#define MAX_CERT_CHAIN_SIZE 0x2000 +#define SHT_QC 0x70000003 +#define SHT_EXIDX 0x70000001 +#define HASH_SE_ALIGN 0x1000 +#define HASH_SE_FLAG 0x2200000 + +int readSecurityDataFromFile(char *buff, std::string root_cert_file_name, std::string atte_cert_file_name) +{ + std::ifstream stream; + // Read ELF file signature + stream.open( atte_cert_file_name, std::ios::in | std::ios::binary ); + if ( !stream ) { + std::cout << "cant open attestation certificate file"<< atte_cert_file_name << std::endl; + return 1; + } + // Read ELF file signature + stream.seekg( 0 ); + int atte_cert_size=0; + for (atte_cert_size = HASH_CODE_SIZE+SIGNATURE_SIZE+sizeof(mi_boot_image_header_type); atte_cert_size < MAX_CERT_CHAIN_SIZE ; atte_cert_size++) + { + if(stream.eof()) break; + stream.read(&buff[atte_cert_size],1); + if(stream.eof()) break; + } + stream.close(); + + stream.open( root_cert_file_name, std::ios::in | std::ios::binary ); + if ( !stream ) { + std::cout << "cant open root certificate file"<< root_cert_file_name << std::endl; + return 1; + } + + stream.seekg( 0 ); + for (; atte_cert_size < MAX_CERT_CHAIN_SIZE ; atte_cert_size++) + { + if(stream.eof()) break; + stream.read(&buff[atte_cert_size],1); + if(stream.eof()) break; + } + + stream.close(); + for (int i=atte_cert_size; i < MAX_CERT_CHAIN_SIZE ; i++) + { + buff[i] = 0xff; + } + return 0; +} + + +int main( int argc, char** argv ) +{ + + if ( argc != 5 ) { + std::cout << "Usage: signlk <unsigned_elf_file> <signed_elf_file> <root_certificate_file> <attestation_CA_certificate_file>" << std::endl; + return 1; + } + // Create an elfio reader and writer + elfio reader; + elfio writer; + char cert_chain[MAX_CERT_CHAIN_SIZE]={0}; + unsigned int hash_segment_address = 0; + std::string root_cert_file_name=(std::string )argv[3]; + std::string atte_cert_file_name=(std::string )argv[4]; + section* data_sec; + Elf_Word maxAddress = 0; + section* maxSec = NULL; + section* mi_sec = NULL; + segment* header_seg = NULL; + segment* hash_seg = NULL; + Elf_Half sec_num; + Elf_Half seg_num; + Elf_Half headerSize; + mi_boot_image_header_type mi={0}; + + /* create a write configuration */ + writer.create( ELFCLASS32, ELFDATA2LSB ); + writer.set_os_abi( ELFOSABI_NONE ); + writer.set_type( ET_EXEC ); + writer.set_machine( EM_ARM ); + writer.set_flags(0x5000002); + + // Load ELF data + if ( !reader.load( argv[1] ) ) { + std::cout << "Can't find or process ELF file " << argv[1] << std::endl; + return 2; + } + + sec_num = reader.sections.size(); + seg_num = reader.segments.size(); + + std::cout << "using attestation certificate file: "<< atte_cert_file_name << std::endl + <<"root certificate file: "<< root_cert_file_name << std::endl + <<"input file: "<<argv[1]<<std::endl + <<"output file: "<<argv[2]<<std::endl; + + /* create new segments for header and hash */ + header_seg = writer.segments.add(); + hash_seg = writer.segments.add(); + + /* copy the original elf segments to the signed elf */ + for ( int i = 0; i < seg_num; ++i ) { + const segment* pseg = reader.segments[i]; + segment* data_seg = writer.segments.add(); + data_seg->set_type( pseg->get_type() ); + data_seg->set_virtual_address( pseg->get_virtual_address() ); + data_seg->set_physical_address( pseg->get_physical_address() ); + data_seg->set_flags( pseg->get_flags() ); + data_seg->set_align( pseg->get_align() ); + data_seg->set_file_size(pseg->get_file_size()); + data_seg->set_memory_size(pseg->get_memory_size()); + } + + /* copy loadable sections to target file*/ + for ( int i = 0; i < sec_num; ++i ) { + section* psec = reader.sections[i]; + + /* copy only loadable sections */ + if ((psec->get_type()==SHT_PROGBITS) + ||(psec->get_type()==SHT_HASH) + ||(psec->get_type()==SHT_EXIDX)) + { + data_sec = writer.sections.add(psec->get_name()); + data_sec->set_type( psec->get_type() ); + data_sec->set_flags( psec->get_flags() ); + data_sec->set_addr_align( psec->get_addr_align() ); + data_sec->set_data( psec->get_data(), psec->get_size() ); + writer.segments[writer.segments.size() - 1]->add_section_index( data_sec->get_index(), data_sec->get_addr_align() ); + } + } + + /* Create data section*/ + headerSize = writer.get_header_size() +(writer.segments.size())*32; + data_sec = writer.sections.add( "" ); + data_sec->set_type( SHT_NULL ); + data_sec->set_flags( SHF_ALLOC ); + data_sec->set_addr_align( 0 ); + char data[0x100]={0}; + data_sec->set_data( data, headerSize ); + + /* Create a read/write segment */ + header_seg->set_type( PT_NULL ); + header_seg->set_virtual_address( 0 ); + header_seg->set_physical_address( 0 ); + header_seg->set_flags( 0 ); + header_seg->set_align( 4 ); + header_seg->set_memory_size(headerSize); + + // Add code section into program segment + header_seg->add_section_index( data_sec->get_index(), data_sec->get_addr_align() ); + + /* scan for the elf file section max address to insert the hash section */ + for ( int i = 0; i < sec_num; ++i ) { + section* psec = reader.sections[i]; + /* copy only loadable sections */ + if ((psec->get_type()==SHT_PROGBITS) + ||(psec->get_type()==SHT_HASH) + ||(psec->get_type()==SHT_EXIDX)) + { + /* store max section address for hash section */ + if (psec->get_address() > maxAddress) + { + maxAddress = psec->get_address(); + maxSec = psec; + } + } + } + + /* calculate section address */ + hash_segment_address = (maxSec->get_address() + (maxSec->get_addr_align() - (maxSec->get_address() % maxSec->get_addr_align()))); + hash_segment_address = (hash_segment_address + (HASH_SE_ALIGN - (hash_segment_address % HASH_SE_ALIGN))); + + /* read the certificates from input files */ + if (readSecurityDataFromFile(cert_chain, root_cert_file_name, atte_cert_file_name)) + { + std::cout << "exiting" << std::endl; + return 1; + } + + /* set the hash segment header data */ + mi.image_id = 0x3; + mi.image_dest_ptr = hash_segment_address + sizeof(mi_boot_image_header_type); + mi.code_size = HASH_CODE_SIZE; + mi.header_vsn_num = 0; + mi.signature_ptr = mi.image_dest_ptr + mi.code_size; + mi.signature_size =SIGNATURE_SIZE; + mi.cert_chain_ptr = mi.signature_ptr + mi.signature_size; + mi.cert_chain_size = CERT_CHAIN_SIZE; + mi.image_size = mi.cert_chain_size + mi.signature_size + mi.code_size; + memcpy(cert_chain,&mi,sizeof(mi)); + + /* create section */ + mi_sec = writer.sections.add( ".mi" ); + mi_sec->set_type( PT_LOPROC ); + mi_sec->set_flags( SHF_ALLOC ); + mi_sec->set_addr_align( HASH_SE_ALIGN ); + mi_sec->set_data( cert_chain, sizeof( cert_chain ) ); + + // Create a read/write segment + hash_seg->set_type( PT_LOPROC); + hash_seg->set_virtual_address( hash_segment_address ); + hash_seg->set_physical_address( hash_segment_address); + hash_seg->set_flags( HASH_SE_FLAG ); + hash_seg->set_align( HASH_SE_ALIGN ); + hash_seg->set_file_size(mi.image_size); + hash_seg->set_memory_size(MAX_CERT_CHAIN_SIZE); + + /* Add code section into program segment */ + hash_seg->add_section_index( mi_sec->get_index(), mi_sec->get_addr_align() ); + + /* set the entry point */ + writer.set_entry(reader.get_entry()); + + /* Create ELF file */ + writer.save(argv[2]); + return 0; +} diff --git a/signlk.sh b/signlk.sh new file mode 100755 index 0000000..954b737 --- /dev/null +++ b/signlk.sh @@ -0,0 +1,134 @@ +################################################################################ +# Copyright (c) 2016, The Linux Foundation. All rights reserved. # +# # +# Redistribution and use in source and binary forms, with or without # +# modification, are permitted provided that the following conditions are # +# met: # +# * Redistributions of source code must retain the above copyright # +# notice, this list of conditions and the following disclaimer. # +# * Redistributions in binary form must reproduce the above # +# copyright notice, this list of conditions and the following # +# disclaimer in the documentation and/or other materials provided # +# with the distribution. # +# * Neither the name of The Linux Foundation nor the names of its # +# contributors may be used to endorse or promote products derived # +# from this software without specific prior written permission. # +# # +# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED # +# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT # +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS # +# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR # +# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, # +# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE # +# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN # +# IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # +# # +# THIS IS A WORKAROUND TO GET LK INTO THE PROPER FORMAT, # +# NO SECURITY IS BEING PROVIDED BY THE OPENSSL CALLS HAPPENING UNDER THE HOOD # +################################################################################ + +INFILE="" +OUTFILE="" +DIR=$(dirname $0) +EXECUTABLE="$DIR/signer/signlk" +CN="" +OU="" +for i in "$@" +do +case $i in + -i=*|--in=*) + INFILE="${i#*=}" + + ;; + -o=*|--out=*) + OUTFILE="${i#*=}" + ;; + -OU=*|-ou=*) + OU="${i#*=}" + + ;; + -CN=*|-cn=*) + CN="${i#*=}" + + ;; + -h*|--help*) + echo "signlk -i=input_file_name [-o=output_file_name]" + echo "-i input ELF/MBN file name" + echo "-o output file name, input_file_name with suffix of 'signed' as default " + exit 0 + ;; + *) + echo "unsupported option" # unknown option + echo "type signlk --help for help" + exit 1 + ;; +esac +done + +if [ "$INFILE" == "" ]; then + echo "signlk -i=input_file_name [-o=output_file_name]" + exit 2 +fi + +INFILE_filename=$(echo $INFILE | rev | cut -f 2- -d '.' | rev) +INFILE_extension=$(echo $INFILE | rev | cut -f 1 -d '.' | rev) + +if [ "$INFILE_extension" == "" ]; then + echo "input file must be an elf or mbn file" + exit 3 +fi + +if [ "$INFILE_extension" != "elf" ] && [ "$INFILE_extension" != "mbn" ] && [ "$INFILE_extension" != "ELF" ] && [ "$INFILE_extension" != "MBN" ]; then + echo "input file must be an elf or mbn file" + exit 4 +fi + +if [ "$OUTFILE" == "" ]; then + OUTFILE=$INFILE_filename"_signed.mbn" + +fi +echo "generating output file $OUTFILE" + +if [ ! -f "$EXECUTABLE" ]; then + echo "building executable..." + export mfile_path=$DIR/signer + make -f $mfile_path/Makefile + + if [ "$?" != 0 ]; then + echo " failed to build executable" + exit 5 + fi +fi +tmp=$(mktemp -d) +tmp_att_file=$tmp/e.ext + +echo "authorityKeyIdentifier=keyid,issuer" >> $tmp_att_file +echo "basicConstraints=CA:FALSE,pathlen:0" >> $tmp_att_file +echo "keyUsage=digitalSignature" >> $tmp_att_file +if [ ! "$(openssl version)" ]; then + echo "please install openssl" + exit 6 +fi +if [ ! "$(make -v)" ]; then + echo "please install gcc" + exit 7 +fi +if [ ! "$(g++ --version)" ]; then + echo "please install g++" + exit 8 +fi +openssl req -new -x509 -keyout $tmp/root_key.PEM -nodes -newkey rsa:2048 -days 7300 -set_serial 1 -sha256 -subj "/CN=$CN/O=$OU/C=/CN=DRAGONBOARD TEST PKI – NOT SECURE/L=/O=S/ST=/OU=01 0000000000000009 SW_ID/OU=02 0000000000000000 HW_ID" > $tmp/root_certificate.PEM 2>/dev/null +openssl x509 -in $tmp/root_certificate.PEM -inform PEM -outform DER > $tmp/root_cert.DER 2>/dev/null +openssl genpkey -algorithm RSA -outform PEM -pkeyopt rsa_keygen_bits:2048 >$tmp/atte_key.PEM 2>/dev/null +openssl req -new -key $tmp/atte_key.PEM -subj "/CN=$CN/O=$OU/C=/CN=DRAGONBOARD TEST PKI – NOT SECURE/L=/O=/ST=/OU=01 0000000000000009 SW_ID/OU=02 0000000000000000 HW_ID" -days 7300 > $tmp/atte_csr.PEM 2>/dev/null +openssl x509 -req -in $tmp/atte_csr.PEM -CAkey $tmp/root_key.PEM -CA $tmp/root_certificate.PEM -days 7300 -set_serial 1 -extfile $tmp_att_file -sha256 -out $tmp/atte_cert.PEM 2>/dev/null +openssl x509 -in $tmp/atte_cert.PEM -inform PEM -outform DER > $tmp/atte_cert.DER 2>/dev/null + +$EXECUTABLE $INFILE $OUTFILE $tmp/root_cert.DER $tmp/atte_cert.DER + +rm -rf $tmp + +echo done |