[<prev] [next>] [day] [month] [year] [list]
Message-Id: <20190430183026.31982-1-yonhan@cisco.com>
Date: Tue, 30 Apr 2019 14:30:26 -0400
From: Yongkui Han <yonhan@...co.com>
To: linux-kernel@...r.kernel.org
Cc: Mehmet Kayaalp <mkayaalp@...ux.vnet.ibm.com>,
David Howells <dhowells@...hat.com>,
Yongkui Han <yonhan@...co.com>
Subject: [PATCH] Brute-force binary-scanning method to extract certificates
Hi Mehmet, David,
I came up with an enhancement to the scripts/extract-sys-certs.pl script
in Linux kernel source, so that the system certificates can be extracted
without debugging symbols or System.map file.
The idea is that the DER-format kernel X509 certificate follows some fixed
pattern. So we can search this fixed pattern to find the location of the
system certificate.
Specifically, below is the pattern I used:
($type0, $len0, $type1, $len1, $ver_attr) =
unpack "nnnnN", substr($fb, $start, 12);
if ($type0 == 0x3082 && $type1 == 0x3082 && $ver_attr == 0xa0030201) {
my $certsize = $len0 + 4;
printf "Have %u bytes of certificate at file offset 0x%x\n",
$certsize, $start;
That is, in the first 12 bytes, two 2-bytes must be 0x3082, and one 4-bytes
must be 0xa0030201. The length of the certificate is also in one of the
2-bytes of the first 12 bytes array.
The script works by scanning the vmlinux file to find this fixed pattern,
and extract the certificate. I think it can be optimized to only scan the
.init* section, instead of the whole vmlinux file. However, the current
approach seems already sufficient.
I have tested with different vmlinux files, and the script works well.
The new script output is like below:
[ bxb-ads-339 ] ./extract-sys-certs.pl vmlinux sys_cert.x509
Have 33 sections
No symbols available, will try brute-force approach.
Length of vmlinux is: 21354392
Have 1063 bytes of certificate at file offset 0x12f99b8
Have 1070 bytes of certificate at file offset 0x12f9ddf
Have 851 bytes of certificate at file offset 0x12fa20d
Have 1188 bytes of certificate at file offset 0x12fa560
Length of extracted certificate is: 4172
[ bxb-ads-339 ]
There is no change if vmlinux contains debugging symbols or System.map
file is provided.
Enclosed please find the git diff output. I can also send you the patch
with “git format-patch” and “git send-email” for you to review.
If possible, can you also try the enhanced script with a few kernel
vmlinux files to test it?
Your review/comments are greatly appreciated.
Thanks,
Yongkui
Signed-off-by: Yongkui Han <yonhan@...co.com>
---
scripts/extract-sys-certs.pl | 44 +++++++++++++++++++++++++++++++++---
1 file changed, 41 insertions(+), 3 deletions(-)
diff --git a/scripts/extract-sys-certs.pl b/scripts/extract-sys-certs.pl
index fa8ab15118cc..06f515b4dcd6 100755
--- a/scripts/extract-sys-certs.pl
+++ b/scripts/extract-sys-certs.pl
@@ -86,6 +86,44 @@ if ($nr_symbols == 0 && $sysmap ne "") {
parse_symbols(@lines);
}
+my $buf = "";
+my $len= 0;
+my $size = 0;
+
+if ($nr_symbols == 0 && $sysmap eq "") {
+ print "No symbols available, will try brute-force approach\n";
+
+ my $filesize = -s $vmlinux;
+ open FD, "<$vmlinux" || die $vmlinux;
+ binmode(FD);
+ my $fb;
+ my $len = sysread(FD, $fb, $filesize);
+ die "$vmlinux" if (!defined($len));
+ die "Short read on $vmlinux\n" if ($len != $filesize);
+ close(FD) || die $vmlinux;
+ printf "Length of vmlinux is: %d\n", length($fb);
+
+ my ($type0, $len0, $type1, $len1, $ver_attr) = (0,0,0,0,0);
+ my $start = 0;
+ while ($start < $filesize - 256) {
+ ($type0, $len0, $type1, $len1, $ver_attr) =
+ unpack "nnnnN", substr($fb, $start, 12);
+ if ($type0 == 0x3082 && $type1 == 0x3082 && $ver_attr == 0xa0030201) {
+ my $certsize = $len0 + 4;
+ printf "Have %u bytes of certificate at file offset 0x%x\n",
+ $certsize, $start;
+ $buf .= substr($fb, $start, $certsize);
+ $start += $certsize;
+ } else {
+ $start += 1;
+ }
+ }
+
+ $size = length($buf);
+ printf "Length of extracted certificate is: %d\n", $size ;
+}
+else {
+
die "No symbols available\n"
if ($nr_symbols == 0);
@@ -97,7 +135,6 @@ die "Can't find system certificate list"
my $start = Math::BigInt->new($symbols{"__cert_list_start"});
my $end;
-my $size;
my $size_sym = Math::BigInt->new($symbols{"system_certificate_list_size"});
open FD, "<$vmlinux" || die $vmlinux;
@@ -145,12 +182,13 @@ my $foff = $start - $s->{vma} + $s->{foff};
printf "Certificate list at file offset 0x%x\n", $foff;
die $vmlinux if (!defined(sysseek(FD, $foff, SEEK_SET)));
-my $buf = "";
-my $len = sysread(FD, $buf, $size);
+$len = sysread(FD, $buf, $size);
die "$vmlinux" if (!defined($len));
die "Short read on $vmlinux\n" if ($len != $size);
close(FD) || die $vmlinux;
+} ### end of ($nr_symbols == 0 && $sysmap eq "") else block
+
open FD, ">$keyring" || die $keyring;
binmode(FD);
$len = syswrite(FD, $buf, $size);
--
2.19.1
Powered by blists - more mailing lists