incore 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. #!/usr/bin/env perl
  2. #
  3. # Copyright (c) 2011 The OpenSSL Project.
  4. #
  5. # The script embeds fingerprint into ELF executable object, either
  6. # application binary or shared library.
  7. ######################################################################
  8. #
  9. # ELF symbol table parser by <appro@openssl.org>. The table entries
  10. # are extended with offset within executable file...
  11. #
  12. { package ELF;
  13. use FileHandle;
  14. sub dup { my %copy=map {$_} @_; return \%copy; }
  15. sub Load {
  16. my $class = shift;
  17. my $self = {};
  18. my $FD = FileHandle->new(); # autoclose
  19. bless $self,$class;
  20. sysopen($FD,shift,0) or die "$!";
  21. binmode($FD);
  22. #################################################
  23. # read and parse elf_ehdr.e_ident...
  24. #
  25. read($FD,my $elf,16) or die "$!";
  26. my %e_ident;
  27. @e_ident{magic,class,data,version,osabi,abiver,pad}=
  28. unpack("a4C*",$elf);
  29. $!=42; # signal fipsld to revert to two-step link
  30. die "not ELF file" if ($e_ident{magic} ne chr(0177)."ELF");
  31. my $elf_bits = $e_ident{class}*32; # 32 or 64
  32. my $big_endian = $e_ident{data}-1; # 0 or 1
  33. if ($elf_bits==64) {
  34. if (!(((1<<31)<<1) && $big_endian==(unpack("L",pack("N",1))==1))) {
  35. die "ELF64 is supported only natively";
  36. }
  37. }
  38. #################################################
  39. # read and parse remainder of elf_ehdr...
  40. #
  41. read($FD,my $elfhdr,64) or die "$!";
  42. my %elf_ehdr;
  43. @elf_ehdr{e_type,e_machine,e_version,
  44. e_entry,e_phoff,e_shoff,e_flags,e_ehsize,
  45. e_phentsize,e_phnum,e_shentsize,e_shnum,e_shstrndx} =
  46. $elf_bits==32 ?
  47. unpack($big_endian?"nnN5n6":"vvV5v6",$elfhdr)
  48. : unpack("SSLQ3LS6",$elfhdr);
  49. # put aside e_machine in case one has to treat specific
  50. # platforms differently, see EM_ constants in elf.h for
  51. # assortment...
  52. $self->{e_machine} = $elf_ehdr{e_machine};
  53. #################################################
  54. # read and parse elf_shdr table...
  55. #
  56. my ($i,$sz,$symtab_idx,$blob,$strings);
  57. seek($FD,$elf_ehdr{e_shoff},0) or die "$!";
  58. read($FD,$blob,$elf_ehdr{e_shentsize}*$elf_ehdr{e_shnum}) or die "$!";
  59. my @sections;
  60. my $elf_shdr_struct=($elf_bits==32?($big_endian?"N10":"V10"):"L2Q4L2Q2");
  61. for ($sz=$elf_ehdr{e_shentsize},$i=0;$i<length($blob);$i+=$sz) {
  62. my %elf_shdr;
  63. @elf_shdr{sh_name,sh_type,sh_flags,
  64. sh_addr,sh_offset,sh_size,
  65. sh_link,sh_info,sh_addalign,sh_entsize} =
  66. unpack($elf_shdr_struct,substr($blob,$i,$sz));
  67. push(@sections,dup(%elf_shdr));
  68. # note SHT_SYMTAB or SHT_DYNSYM for future reference
  69. if ($elf_shdr{sh_type}==2 || $elf_shdr{sh_type}==11) {
  70. $symtab_idx = $#sections;
  71. }
  72. }
  73. # read strings table and map section names...
  74. seek($FD,@sections[$elf_ehdr{e_shstrndx}]->{sh_offset},0) or die "$!";
  75. read($FD,$strings,@sections[$elf_ehdr{e_shstrndx}]->{sh_size}) or die "$!";
  76. for (@sections) {
  77. $_->{sh_name}=(split(chr(0),substr($strings,$_->{sh_name},64)))[0];
  78. }
  79. #################################################
  80. # read symbol strings table...
  81. #
  82. $i=@sections[$symtab_idx]->{sh_link};
  83. seek($FD,@sections[$i]->{sh_offset},0) or die "$!";
  84. read($FD,$strings,@sections[$i]->{sh_size}) or die "$!";
  85. #################################################
  86. # read and parse elf_sym table...
  87. #
  88. seek($FD,@sections[$symtab_idx]->{sh_offset},0) or die "$!";
  89. read($FD,my $blob,@sections[$symtab_idx]->{sh_size}) or die "$!";
  90. for ($sz=@sections[$symtab_idx]->{sh_entsize},$i=0;$i<length($blob);$i+=$sz) {
  91. my %elf_sym;
  92. if ($elf_bits==32) {
  93. @elf_sym{st_name,st_value,st_size,st_info,st_other,st_shndx} =
  94. unpack($big_endian?"N3CCn":"V3CCv",substr($blob,$i,$sz));
  95. } else {
  96. @elf_sym{st_name,st_info,st_other,st_shndx,st_value,st_size} =
  97. unpack("LCCSQQ",substr($blob,$i,$sz));
  98. }
  99. my $st_type = $elf_sym{st_info}&0xf;
  100. my $st_bind = $elf_sym{st_info}>>4;
  101. my $st_secn = $elf_sym{st_shndx};
  102. my $name;
  103. # (STT_OBJECT || STT_FUNC)
  104. if ($st_bind<3 && ($st_type==1 || $st_type==2)
  105. && $st_secn <= $#sections # sane st_shndx
  106. && @sections[$st_secn]->{sh_type} # not SHN_UNDEF
  107. && ($name=(split(chr(0),substr($strings,$elf_sym{st_name},128)))[0])
  108. ) {
  109. # synthesize st_offset, ...
  110. $elf_sym{st_offset} = $elf_sym{st_value}
  111. - @sections[$st_secn]->{sh_addr}
  112. + @sections[$st_secn]->{sh_offset};
  113. $elf_sym{st_name} = $name;
  114. $elf_sym{st_section} = @sections[$st_secn]->{sh_name};
  115. # ... and add to lookup table
  116. $self->{symbols}{$name} = dup(%elf_sym);
  117. }
  118. }
  119. return $self;
  120. }
  121. sub Lookup {
  122. my $self = shift;
  123. my $name = shift;
  124. return $self->{symbols}{$name};
  125. }
  126. sub Traverse {
  127. my $self = shift;
  128. my $code = shift;
  129. if (ref($code) eq 'CODE') {
  130. for (keys(%{$self->{symbols}})) { &$code($self->{symbols}{$_}); }
  131. }
  132. }
  133. }
  134. ######################################################################
  135. #
  136. # SHA1 and HMAC in Perl by <appro@openssl.org>.
  137. #
  138. { package SHA1;
  139. use integer;
  140. {
  141. ################################### SHA1 block code generator
  142. my @V = ('$A','$B','$C','$D','$E');
  143. my $i;
  144. sub XUpdate {
  145. my $ret;
  146. $ret="(\$T=\$W[($i-16)%16]^\$W[($i-14)%16]^\$W[($i-8)%16]^\$W[($i-3)%16],\n\t";
  147. if ((1<<31)<<1) {
  148. $ret.=" \$W[$i%16]=((\$T<<1)|(\$T>>31))&0xffffffff)\n\t ";
  149. } else {
  150. $ret.=" \$W[$i%16]=(\$T<<1)|((\$T>>31)&1))\n\t ";
  151. }
  152. }
  153. sub tail {
  154. my ($a,$b,$c,$d,$e)=@V;
  155. my $ret;
  156. if ((1<<31)<<1) {
  157. $ret.="(($a<<5)|($a>>27));\n\t";
  158. $ret.="$b=($b<<30)|($b>>2); $e&=0xffffffff; #$b&=0xffffffff;\n\t";
  159. } else {
  160. $ret.="(($a<<5)|($a>>27)&0x1f);\n\t";
  161. $ret.="$b=($b<<30)|($b>>2)&0x3fffffff;\n\t";
  162. }
  163. $ret;
  164. }
  165. sub BODY_00_15 {
  166. my ($a,$b,$c,$d,$e)=@V;
  167. "$e+=\$W[$i]+0x5a827999+((($c^$d)&$b)^$d)+".tail();
  168. }
  169. sub BODY_16_19 {
  170. my ($a,$b,$c,$d,$e)=@V;
  171. "$e+=".XUpdate()."+0x5a827999+((($c^$d)&$b)^$d)+".tail();
  172. }
  173. sub BODY_20_39 {
  174. my ($a,$b,$c,$d,$e)=@V;
  175. "$e+=".XUpdate()."+0x6ed9eba1+($b^$c^$d)+".tail();
  176. }
  177. sub BODY_40_59 {
  178. my ($a,$b,$c,$d,$e)=@V;
  179. "$e+=".XUpdate()."+0x8f1bbcdc+(($b&$c)|(($b|$c)&$d))+".tail();
  180. }
  181. sub BODY_60_79 {
  182. my ($a,$b,$c,$d,$e)=@V;
  183. "$e+=".XUpdate()."+0xca62c1d6+($b^$c^$d)+".tail();
  184. }
  185. my $sha1_impl =
  186. 'sub block {
  187. my $self = @_[0];
  188. my @W = unpack("N16",@_[1]);
  189. my ($A,$B,$C,$D,$E,$T) = @{$self->{H}};
  190. ';
  191. $sha1_impl.='
  192. $A &= 0xffffffff;
  193. $B &= 0xffffffff;
  194. ' if ((1<<31)<<1);
  195. for($i=0;$i<16;$i++){ $sha1_impl.=BODY_00_15(); unshift(@V,pop(@V)); }
  196. for(;$i<20;$i++) { $sha1_impl.=BODY_16_19(); unshift(@V,pop(@V)); }
  197. for(;$i<40;$i++) { $sha1_impl.=BODY_20_39(); unshift(@V,pop(@V)); }
  198. for(;$i<60;$i++) { $sha1_impl.=BODY_40_59(); unshift(@V,pop(@V)); }
  199. for(;$i<80;$i++) { $sha1_impl.=BODY_60_79(); unshift(@V,pop(@V)); }
  200. $sha1_impl.='
  201. $self->{H}[0]+=$A; $self->{H}[1]+=$B; $self->{H}[2]+=$C;
  202. $self->{H}[3]+=$D; $self->{H}[4]+=$E; }';
  203. #print $sha1_impl,"\n";
  204. eval($sha1_impl); # generate code
  205. }
  206. sub Init {
  207. my $class = shift; # multiple instances...
  208. my $self = {};
  209. bless $self,$class;
  210. $self->{H} = [0x67452301,0xefcdab89,0x98badcfe,0x10325476,0xc3d2e1f0];
  211. $self->{N} = 0;
  212. return $self;
  213. }
  214. sub Update {
  215. my $self = shift;
  216. my $msg;
  217. foreach $msg (@_) {
  218. my $len = length($msg);
  219. my $num = length($self->{buf});
  220. my $off = 0;
  221. $self->{N} += $len;
  222. if (($num+$len)<64)
  223. { $self->{buf} .= $msg; next; }
  224. elsif ($num)
  225. { $self->{buf} .= substr($msg,0,($off=64-$num));
  226. $self->block($self->{buf});
  227. }
  228. while(($off+64) <= $len)
  229. { $self->block(substr($msg,$off,64));
  230. $off += 64;
  231. }
  232. $self->{buf} = substr($msg,$off);
  233. }
  234. return $self;
  235. }
  236. sub Final {
  237. my $self = shift;
  238. my $num = length($self->{buf});
  239. $self->{buf} .= chr(0x80); $num++;
  240. if ($num>56)
  241. { $self->{buf} .= chr(0)x(64-$num);
  242. $self->block($self->{buf});
  243. $self->{buf}=undef;
  244. $num=0;
  245. }
  246. $self->{buf} .= chr(0)x(56-$num);
  247. $self->{buf} .= pack("N2",($self->{N}>>29)&0x7,$self->{N}<<3);
  248. $self->block($self->{buf});
  249. return pack("N*",@{$self->{H}});
  250. }
  251. sub Selftest {
  252. my $hash;
  253. $hash=SHA1->Init()->Update('abc')->Final();
  254. die "SHA1 test#1" if (unpack("H*",$hash) ne 'a9993e364706816aba3e25717850c26c9cd0d89d');
  255. $hash=SHA1->Init()->Update('abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq')->Final();
  256. die "SHA1 test#2" if (unpack("H*",$hash) ne '84983e441c3bd26ebaae4aa1f95129e5e54670f1');
  257. #$hash=SHA1->Init()->Update('a'x1000000)->Final();
  258. #die "SHA1 test#3" if (unpack("H*",$hash) ne '34aa973cd4c4daa4f61eeb2bdbad27316534016f');
  259. }
  260. }
  261. { package HMAC;
  262. sub Init {
  263. my $class = shift;
  264. my $key = shift;
  265. my $self = {};
  266. bless $self,$class;
  267. if (length($key)>64) {
  268. $key = SHA1->Init()->Update($key)->Final();
  269. }
  270. $key .= chr(0x00)x(64-length($key));
  271. my @ikey = map($_^=0x36,unpack("C*",$key));
  272. ($self->{hash} = SHA1->Init())->Update(pack("C*",@ikey));
  273. $self->{okey} = pack("C*",map($_^=0x36^0x5c,@ikey));
  274. return $self;
  275. }
  276. sub Update {
  277. my $self = shift;
  278. $self->{hash}->Update(@_);
  279. return $self;
  280. }
  281. sub Final {
  282. my $self = shift;
  283. my $ihash = $self->{hash}->Final();
  284. return SHA1->Init()->Update($self->{okey},$ihash)->Final();
  285. }
  286. sub Selftest {
  287. my $hmac;
  288. $hmac = HMAC->Init('0123456789:;<=>?@ABC')->Update('Sample #2')->Final();
  289. die "HMAC test" if (unpack("H*",$hmac) ne '0922d3405faa3d194f82a45830737d5cc6c75d24');
  290. }
  291. }
  292. ######################################################################
  293. #
  294. # main()
  295. #
  296. my $legacy_mode;
  297. if ($ARGV<0 || ($#ARGV>0 && !($legacy_mode=(@ARGV[0] =~ /^\-(dso|exe)$/)))) {
  298. print STDERR "usage: $0 [-dso|-exe] elfbinary\n";
  299. exit(1);
  300. }
  301. $exe = ELF->Load(@ARGV[$#ARGV]);
  302. $FIPS_text_start = $exe->Lookup("FIPS_text_start") or die;
  303. $FIPS_text_end = $exe->Lookup("FIPS_text_end") or die;
  304. $FIPS_rodata_start = $exe->Lookup("FIPS_rodata_start") or die;
  305. $FIPS_rodata_end = $exe->Lookup("FIPS_rodata_end") or die;
  306. $FIPS_signature = $exe->Lookup("FIPS_signature") or die;
  307. # new cross-compile support
  308. $FIPS_text_startX = $exe->Lookup("FIPS_text_startX");
  309. $FIPS_text_endX = $exe->Lookup("FIPS_text_endX");
  310. if (!$legacy_mode) {
  311. if (!$FIPS_text_startX || !$FIPS_text_endX) {
  312. print STDERR "@ARGV[$#ARGV] is not cross-compiler aware.\n";
  313. exit(42); # signal fipsld to revert to two-step link
  314. }
  315. $FINGERPRINT_ascii_value
  316. = $exe->Lookup("FINGERPRINT_ascii_value");
  317. }
  318. if ($FIPS_text_startX && $FIPS_text_endX) {
  319. $FIPS_text_start = $FIPS_text_startX;
  320. $FIPS_text_end = $FIPS_text_endX;
  321. }
  322. sysopen(FD,@ARGV[$#ARGV],$legacy_mode?0:2) or die "$!"; # 2 is read/write
  323. binmode(FD);
  324. sub HMAC_Update {
  325. my ($hmac,$off,$len) = @_;
  326. my $blob;
  327. seek(FD,$off,0) or die "$!";
  328. read(FD,$blob,$len) or die "$!";
  329. $$hmac->Update($blob);
  330. }
  331. # fips/fips.c:FIPS_incore_fingerprint's Perl twin
  332. #
  333. sub FIPS_incore_fingerprint {
  334. my $p1 = $FIPS_text_start->{st_offset};
  335. my $p2 = $FIPS_text_end->{st_offset};
  336. my $p3 = $FIPS_rodata_start->{st_offset};
  337. my $p4 = $FIPS_rodata_end->{st_offset};
  338. my $sig = $FIPS_signature->{st_offset};
  339. my $ctx = HMAC->Init("etaonrishdlcupfm");
  340. # detect overlapping regions
  341. if ($p1<=$p3 && $p2>=$p3) {
  342. $p3 = $p1; $p4 = $p2>$p4?$p2:$p4; $p1 = 0; $p2 = 0;
  343. } elsif ($p3<=$p1 && $p4>=$p1) {
  344. $p3 = $p3; $p4 = $p2>$p4?$p2:$p4; $p1 = 0; $p2 = 0;
  345. }
  346. if ($p1) {
  347. HMAC_Update (\$ctx,$p1,$p2-$p1);
  348. }
  349. if ($sig>=$p3 && $sig<$p4) {
  350. # "punch" hole
  351. HMAC_Update(\$ctx,$p3,$sig-$p3);
  352. $p3 = $sig+20;
  353. HMAC_Update(\$ctx,$p3,$p4-$p3);
  354. } else {
  355. HMAC_Update(\$ctx,$p3,$p4-$p3);
  356. }
  357. return $ctx->Final();
  358. }
  359. $fingerprint = FIPS_incore_fingerprint();
  360. if ($legacy_mode) {
  361. print unpack("H*",$fingerprint);
  362. } elsif (defined($FINGERPRINT_ascii_value)) {
  363. seek(FD,$FINGERPRINT_ascii_value->{st_offset},0) or die "$!";
  364. print FD unpack("H*",$fingerprint) or die "$!";
  365. } else {
  366. seek(FD,$FIPS_signature->{st_offset},0) or die "$!";
  367. print FD $fingerprint or die "$!";
  368. }
  369. close (FD);