From: Andy Polyakov Date: Fri, 22 Jul 2011 09:42:11 +0000 (+0000) Subject: fips_canister.c: add support for embedded ppc linux. X-Git-Tag: OpenSSL-fips-2_0-rc1~245 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=167cb62537854908ba44a4aadb4e03f750297569;p=openssl fips_canister.c: add support for embedded ppc linux. --- diff --git a/fips/fips_canister.c b/fips/fips_canister.c index 08d07e4b00..a1f8400479 100644 --- a/fips/fips_canister.c +++ b/fips/fips_canister.c @@ -29,7 +29,8 @@ const void *FIPS_text_end(void); #if !defined(FIPS_REF_POINT_IS_CROSS_COMPILER_AWARE) # if (defined(__ANDROID__) && (defined(__arm__) || defined(__arm))) || \ - (defined(__vxworks) && (defined(__ppc__) || defined(__ppc))) + (defined(__vxworks) && (defined(__ppc__) || defined(__ppc))) || \ + (defined(__linux) && defined(__PPC__) && !defined(__PPC64__)) # define FIPS_REF_POINT_IS_CROSS_COMPILER_AWARE # endif #endif @@ -46,7 +47,10 @@ static void *instruction_pointer_xlc(void); #endif #ifdef FIPS_START -#define FIPS_ref_point FIPS_text_start +# define FIPS_ref_point FIPS_text_start +# ifdef FIPS_REF_POINT_IS_CROSS_COMPILER_AWARE +# define instruction_pointer FIPS_text_startX +# endif /* Some compilers put string literals into a separate segment. As we * are mostly interested to hash AES tables in .rodata, we declare * reference points accordingly. In case you wonder, the values are @@ -55,7 +59,10 @@ static void *instruction_pointer_xlc(void); const unsigned int FIPS_rodata_start[]= { 0x46495053, 0x5f726f64, 0x6174615f, 0x73746172 }; #else -#define FIPS_ref_point FIPS_text_end +# define FIPS_ref_point FIPS_text_end +# ifdef FIPS_REF_POINT_IS_CROSS_COMPILER_AWARE +# define instruction_pointer FIPS_text_endX +# endif const unsigned int FIPS_rodata_end[]= { 0x46495053, 0x5f726f64, 0x6174615f, 0x656e645b }; #endif @@ -150,7 +157,7 @@ static void *instruction_pointer(void) const void *FIPS_ref_point() { #if defined(FIPS_REF_POINT_IS_CROSS_COMPILER_AWARE) - return (void *)FIPS_ref_point; + return (void *)instruction_pointer; #elif defined(INSTRUCTION_POINTER_IMPLEMENTED) return instruction_pointer(); /* Below we essentially cover vendor compilers which do not support diff --git a/util/incore b/util/incore new file mode 100755 index 0000000000..ee495ee352 --- /dev/null +++ b/util/incore @@ -0,0 +1,440 @@ +#!/usr/bin/env perl +# +# Copyrifgr (c) 2011 The OpenSSL Project. +# +# The script embeds fingerprint into ELF executable object, either +# application binary or shared library. + +###################################################################### +# +# ELF symbol table parser by . The table entries +# are extended with offset within executable file... +# +{ package ELF; + use FileHandle; + + sub dup { my %copy=map {$_} @_; return \%copy; } + + sub Load { + my $class = shift; + my $self = {}; + my $FD = FileHandle->new(); # autoclose + + bless $self,$class; + + sysopen($FD,shift,0) or die "$!"; + binmode($FD); + + ################################################# + # read and parse elf_ehdr.e_ident... + # + read($FD,my $elf,16) or die "$!"; + + my %e_ident; + @e_ident{magic,class,data,version,osabi,abiver,pad}= + unpack("a4C*",$elf); + + die "not ELF file" if ($e_ident{magic} ne chr(0177)."ELF"); + + my $elf_bits = $e_ident{class}*32; # 32 or 64 + my $big_endian = $e_ident{data}-1; # 0 or 1 + + if ($elf_bits==64) { + if (!(((1<<31)<<1) && $big_endian==(unpack("L",pack("N",1))==1))) { + die "ELF64 is supported only natively"; + } + } + + ################################################# + # read and parse remainder of elf_ehdr... + # + read($FD,my $elfhdr,64) or die "$!"; + + my %elf_ehdr; + @elf_ehdr{e_type,e_machine,e_version, + e_entry,e_phoff,e_shoff,e_flags,e_ehsize, + e_phentsize,e_phnum,e_shentsize,e_shnum,e_shstrndx} = + $elf_bits==32 ? + unpack($big_endian?"nnN5n6":"vvV5v6",$elfhdr) + : unpack("SSLQ3LS6",$elfhdr); + + # put aside e_machine in case one has to treat specific + # platforms differently, see EM_ constants in elf.h for + # assortment... + $self->{e_machine} = $elf_ehdr{e_machine}; + + ################################################# + # read and parse elf_shdr table... + # + my ($i,$sz,$symtab_idx,$blob,$strings); + + seek($FD,$elf_ehdr{e_shoff},0) or die "$!"; + read($FD,$blob,$elf_ehdr{e_shentsize}*$elf_ehdr{e_shnum}) or die "$!"; + + my @sections; + my $elf_shdr_struct=($elf_bits==32?($big_endian?"N10":"V10"):"L2Q4L2Q2"); + for ($sz=$elf_ehdr{e_shentsize},$i=0;$i{sh_offset},0) or die "$!"; + read($FD,$strings,@sections[$elf_ehdr{e_shstrndx}]->{sh_size}) or die "$!"; + for (@sections) { + $_->{sh_name}=(split(chr(0),substr($strings,$_->{sh_name},64)))[0]; + } + + ################################################# + # read symbol strings table... + # + $i=@sections[$symtab_idx]->{sh_link}; + seek($FD,@sections[$i]->{sh_offset},0) or die "$!"; + read($FD,$strings,@sections[$i]->{sh_size}) or die "$!"; + + ################################################# + # read and parse elf_sym table... + # + seek($FD,@sections[$symtab_idx]->{sh_offset},0) or die "$!"; + read($FD,my $blob,@sections[$symtab_idx]->{sh_size}) or die "$!"; + + for ($sz=@sections[$symtab_idx]->{sh_entsize},$i=0;$i>4; + my $st_secn = $elf_sym{st_shndx}; + my $name; + # (STT_OBJECT || STT_FUNC) + if ($st_bind<3 && ($st_type==1 || $st_type==2) + && $st_secn <= $#sections # sane st_shndx + && @sections[$st_secn]->{sh_type} # not SHN_UNDEF + && ($name=(split(chr(0),substr($strings,$elf_sym{st_name},128)))[0]) + ) { + # synthesize st_offset, ... + $elf_sym{st_offset} = $elf_sym{st_value} + - @sections[$st_secn]->{sh_addr} + + @sections[$st_secn]->{sh_offset}; + $elf_sym{st_name} = $name; + $elf_sym{st_section} = @sections[$st_secn]->{sh_name}; + # ... and add to lookup table + $self->{symbols}{$name} = dup(%elf_sym); + } + } + + return $self; + } + + sub Lookup { + my $self = shift; + my $name = shift; + return $self->{symbols}{$name}; + } + + sub Traverse { + my $self = shift; + my $code = shift; + + if (ref($code) eq 'CODE') { + for (keys(%{$self->{symbols}})) { &$code($self->{symbols}{$_}); } + } + } +} + +###################################################################### +# +# SHA1 and HMAC in Perl by . +# +{ package SHA1; + use integer; + + { + ################################### SHA1 block code generator + my @V = ('$A','$B','$C','$D','$E'); + my $i; + + sub XUpdate { + my $ret; + $ret="(\$T=\$W[($i-16)%16]^\$W[($i-14)%16]^\$W[($i-8)%16]^\$W[($i-3)%16],\n\t"; + if ((1<<31)<<1) { + $ret.=" \$W[$i%16]=((\$T<<1)|(\$T>>31))&0xffffffff)\n\t "; + } else { + $ret.=" \$W[$i%16]=(\$T<<1)|((\$T>>31)&1))\n\t "; + } + } + sub tail { + my ($a,$b,$c,$d,$e)=@V; + my $ret; + if ((1<<31)<<1) { + $ret.="(($a<<5)|($a>>27));\n\t"; + $ret.="$b=($b<<30)|($b>>2); $e&=0xffffffff; #$b&=0xffffffff;\n\t"; + } else { + $ret.="(($a<<5)|($a>>27)&0x1f);\n\t"; + $ret.="$b=($b<<30)|($b>>2)&0x3fffffff;\n\t"; + } + $ret; + } + sub BODY_00_15 { + my ($a,$b,$c,$d,$e)=@V; + "$e+=\$W[$i]+0x5a827999+((($c^$d)&$b)^$d)+".tail(); + } + sub BODY_16_19 { + my ($a,$b,$c,$d,$e)=@V; + "$e+=".XUpdate()."+0x5a827999+((($c^$d)&$b)^$d)+".tail(); + } + sub BODY_20_39 { + my ($a,$b,$c,$d,$e)=@V; + "$e+=".XUpdate()."+0x6ed9eba1+($b^$c^$d)+".tail(); + } + sub BODY_40_59 { + my ($a,$b,$c,$d,$e)=@V; + "$e+=".XUpdate()."+0x8f1bbcdc+(($b&$c)|(($b|$c)&$d))+".tail(); + } + sub BODY_60_79 { + my ($a,$b,$c,$d,$e)=@V; + "$e+=".XUpdate()."+0xca62c1d6+($b^$c^$d)+".tail(); + } + + my $sha1_impl = + 'sub block { + my $self = @_[0]; + my @W = unpack("N16",@_[1]); + my ($A,$B,$C,$D,$E,$T) = @{$self->{H}}; + '; + + $sha1_impl.=' + $A &= 0xffffffff; + $B &= 0xffffffff; + ' if ((1<<31)<<1); + + for($i=0;$i<16;$i++){ $sha1_impl.=BODY_00_15(); unshift(@V,pop(@V)); } + for(;$i<20;$i++) { $sha1_impl.=BODY_16_19(); unshift(@V,pop(@V)); } + for(;$i<40;$i++) { $sha1_impl.=BODY_20_39(); unshift(@V,pop(@V)); } + for(;$i<60;$i++) { $sha1_impl.=BODY_40_59(); unshift(@V,pop(@V)); } + for(;$i<80;$i++) { $sha1_impl.=BODY_60_79(); unshift(@V,pop(@V)); } + + $sha1_impl.=' + $self->{H}[0]+=$A; $self->{H}[1]+=$B; $self->{H}[2]+=$C; + $self->{H}[3]+=$D; $self->{H}[4]+=$E; }'; + + #print $sha1_impl,"\n"; + eval($sha1_impl); # generate code + } + + sub Init { + my $class = shift; # multiple instances... + my $self = {}; + + bless $self,$class; + $self->{H} = [0x67452301,0xefcdab89,0x98badcfe,0x10325476,0xc3d2e1f0]; + $self->{N} = 0; + return $self; + } + + sub Update { + my $self = shift; + my $msg; + + foreach $msg (@_) { + my $len = length($msg); + my $num = length($self->{buf}); + my $off = 0; + + $self->{N} += $len; + + if (($num+$len)<64) + { $self->{buf} .= $msg; next; } + elsif ($num) + { $self->{buf} .= substr($msg,0,($off=64-$num)); + $self->block($self->{buf}); + } + + while(($off+64) <= $len) + { $self->block(substr($msg,$off,64)); + $off += 64; + } + + $self->{buf} = substr($msg,$off); + } + return $self; + } + + sub Final { + my $self = shift; + my $num = length($self->{buf}); + + $self->{buf} .= chr(0x80); $num++; + if ($num>56) + { $self->{buf} .= chr(0)x(64-$num); + $self->block($self->{buf}); + $self->{buf}=undef; + $num=0; + } + $self->{buf} .= chr(0)x(56-$num); + $self->{buf} .= pack("N2",($self->{N}>>29)&0x7,$self->{N}<<3); + $self->block($self->{buf}); + + return pack("N*",@{$self->{H}}); + } + + sub Selftest { + my $hash; + + $hash=SHA1->Init()->Update('abc')->Final(); + die "SHA1 test#1" if (unpack("H*",$hash) ne 'a9993e364706816aba3e25717850c26c9cd0d89d'); + + $hash=SHA1->Init()->Update('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')->Final(); + die "SHA1 test#2" if (unpack("H*",$hash) ne '84983e441c3bd26ebaae4aa1f95129e5e54670f1'); + + #$hash=SHA1->Init()->Update('a'x1000000)->Final(); + #die "SHA1 test#3" if (unpack("H*",$hash) ne '34aa973cd4c4daa4f61eeb2bdbad27316534016f'); + } +} + +{ package HMAC; + + sub Init { + my $class = shift; + my $key = shift; + my $self = {}; + + bless $self,$class; + + if (length($key)>64) { + $key = SHA1->Init()->Update($key)->Final(); + } + $key .= chr(0x00)x(64-length($key)); + + my @ikey = map($_^=0x36,unpack("C*",$key)); + ($self->{hash} = SHA1->Init())->Update(pack("C*",@ikey)); + $self->{okey} = pack("C*",map($_^=0x36^0x5c,@ikey)); + + return $self; + } + + sub Update { + my $self = shift; + $self->{hash}->Update(@_); + return $self; + } + + sub Final { + my $self = shift; + my $ihash = $self->{hash}->Final(); + return SHA1->Init()->Update($self->{okey},$ihash)->Final(); + } + + sub Selftest { + my $hmac; + + $hmac = HMAC->Init('0123456789:;<=>?@ABC')->Update('Sample #2')->Final(); + die "HMAC test" if (unpack("H*",$hmac) ne '0922d3405faa3d194f82a45830737d5cc6c75d24'); + } +} + +###################################################################### +# +# main() +# +my $legacy_mode; + +if ($ARGV<0 || ($#ARGV>0 && !($legacy_mode=(@ARGV[0] =~ /^\-(dso|exe)$/)))) { + print STDERR "usage: $0 [-dso|-exe] elfbinary\n"; + exit(1); +} + +$exe = ELF->Load(@ARGV[$#ARGV]); + +$FIPS_text_start = $exe->Lookup("FIPS_text_start") or die; +$FIPS_text_end = $exe->Lookup("FIPS_text_end") or die; +$FIPS_rodata_start = $exe->Lookup("FIPS_rodata_start") or die; +$FIPS_rodata_end = $exe->Lookup("FIPS_rodata_end") or die; +$FIPS_signature = $exe->Lookup("FIPS_signature") or die; + +if (!$legacy_mode) { + $FIPS_text_start = $exe->Lookup("FIPS_text_startX"); + $FIPS_text_end = $exe->Lookup("FIPS_text_endX"); + + if (!$FIPS_text_start || !$FIPS_text_end) { + print STDERR "@ARGV[$#ARGV] is not cross-compiler aware.\n"; + exit(1); + } + + $FINGERPRINT_ascii_value + = $exe->Lookup("FINGERPRINT_ascii_value") or die; +} + +sysopen(FD,@ARGV[$#ARGV],$legacy_mode?0:2) or die "$!"; # 2 is read/write +binmode(FD); + +sub HMAC_Update { + my ($hmac,$off,$len) = @_; + my $blob; + + seek(FD,$off,0) or die "$!"; + read(FD,$blob,$len) or die "$!"; + $$hmac->Update($blob); +} + +# fips/fips.c:FIPS_incore_fingerprint's Perl twin +# +sub FIPS_incore_fingerprint { + my $p1 = $FIPS_text_start->{st_offset}; + my $p2 = $FIPS_text_end->{st_offset}; + my $p3 = $FIPS_rodata_start->{st_offset}; + my $p4 = $FIPS_rodata_end->{st_offset}; + my $sig = $FIPS_signature->{st_offset}; + my $ctx = HMAC->Init("etaonrishdlcupfm"); + + # detect overlapping regions + if ($p1<=$p3 && $p2>=$p3) { + $p3 = $p1; $p4 = $p2>$p4?$p2:$p4; $p1 = 0; $p2 = 0; + } elsif ($p3<=$p1 && $p4>=$p1) { + $p3 = $p3; $p4 = $p2>$p4?$p2:$p4; $p1 = 0; $p2 = 0; + } + + if ($p1) { + HMAC_Update (\$ctx,$p1,$p2-$p1); + } + + if ($sig>=$p3 && $sig<$p4) { + # "punch" hole + HMAC_Update(\$ctx,$p3,$sig-$p3); + $p3 = $sig+20; + HMAC_Update(\$ctx,$p3,$p4-$p3); + } else { + HMAC_Update(\$ctx,$p3,$p4-$p3); + } + + return $ctx->Final(); +} + +$fingerprint = FIPS_incore_fingerprint(); + +if ($legacy_mode) { + print unpack("H*",$fingerprint); +} else { + seek(FD,$FINGERPRINT_ascii_value->{st_offset},0) or die "$!"; + print FD unpack("H*",$fingerprint) or die "$!"; +} + +close (FD);