如何验证内核模块签名?

米哈伊尔·莫尔菲科夫(Mikhail Morfikov)

编译内核源代码时,可以选择使用CONFIG_MODULE_SIG*选项对内核模块进行签名modinfo工具应该执行验证模块签名的任务,但是多年来存在一些错误,该工具根本无法胜任。我所得到的是以下内容:

sig_id:         PKCS#7
signer:
sig_key:
sig_hashalgo:   md4
signature:      30:82:02:F4:06:09:2A:86:48:86:F7:0D:01:07:02:A0:82:02:E5:30:
                ...

因此没有密钥,哈希算法是md4,它甚至没有在内核中编译。

那么如何手动检查和验证模块签名呢?那有可能吗?

满天星

是的,这是可能的,但确实涉及其中。

首先,您必须提取模块签名-您可以extract-module.sig.pl从内核源代码中使用脚本:

$ scripts/extract-module-sig.pl -s MODULE.ko >/tmp/modsig.
Read 789006 bytes from module file
Found magic number at 789006
Found PKCS#7/CMS encapsulation
Found 670 bytes of signature [3082029a06092a864886f70d010702a0]

其次,您必须从内核中提取证书和公共密钥。您可以extract-sys-certs.pl为此使用脚本:

$ scripts/extract-sys-certs.pl /PATH/TO/vmlinux /tmp/cert.x509
Have 32 sections
Have 28167 symbols
Have 1346 bytes of certs at VMA 0xffffffff81be6db8
Certificate list in section .init.data
Certificate list at file offset 0xde6db8
$ openssl x509 -pubkey -noout -inform der -in /tmp/cert.x509 -out /tmp/pubkey

您还可以从Linux内核的build目录中certs/signing_key.x509certs/signing_key.pem文件中提取公钥

完成此操作后,您便拥有了所需的所有数据/tmp/modsig/tmp/cert.x509并且可以继续执行大约十二个步骤来验证PKCS#7签名。

您可以查看此博客文章,了解整个食谱。


我试图将整个过程(extract-certs.pl步骤除外)放在perl脚本中。

您可以像这样使用它:

perl checkmodsig.pl /path/to/cert.x509 mod1.ko mod2.ko ...

YMMV我只使用使用sha512签名的自定义内核尝试过此操作。这应该是当然更好的完成直接使用OpenSSL库,而不是kludging一起缓慢和脆弱openssl x509asn1parsersautl调用。

checkmodsig.pl

use strict;

sub through {
    my ($cmd, $data, $cb) = @_;
    use IPC::Open2;
    my $pid = open2 my $from, my $to, ref $cmd ? @$cmd : $cmd;
    print $to $data; close $to; my $out;
    if($cb){ while(<$from>){ last if $out = $cb->($_) } }
    else { local $/; $out = <$from>; }
    waitpid ($pid, 0);
    die "status $?" if $? != 0;
    $out;
}
sub gethash {
    my ($d) = @_; my ($alg, $hash);
    through [qw(openssl asn1parse -inform der)], $d, sub {
        if(/(\d+):d=\d+ +hl= *(\d+) +l= *(\d+) +prim: +OCTET STRING/){
            $hash = substr $d, $1 + $2, $3
        }elsif(/prim: +OBJECT +:(sha\w+)/){
            $alg = $1;
        }
        undef
    };
    $alg, $hash
}

use File::Temp;
my $tf = new File::Temp;
my $pub_key;
my @type = qw(PGP X509 PKCS7);
my $r = 0;
if((my $cert = shift) =~ /(\.x509)$|\.pem$/i){
    $pub_key = $tf->filename;
    system qw(openssl x509 -pubkey -noout),
        '-inform', $1 ? 'der' : 'pem',
        '-in', $cert, '-out', $pub_key;
    die "status $?" if $? != 0;
}
die "no certificate/key file" unless $pub_key;
for my $kof (@ARGV){
    open my $ko, '<', $kof or die "open $kof: $!\n";
    seek $ko, -4096, 2 or die "seek: $!";
    read $ko, my $d, 4096 or die "read: $!";
    my ($algo, $hash, $type, $signer_len, $key_id_len, $sig_len, $magic) =
        unpack 'C5x3Na*', substr $d, -40;
    die "no signature in $kof"
        unless $magic eq "~Module signature appended~\n";
    die "this script only knows about PKCS#7 signatures"
        unless $type[$type] eq 'PKCS7';

    my $hash = gethash substr $d, - 40 - $sig_len, $sig_len;
    die "hash not found" unless $hash;

    my ($alg, $vhash) = gethash
        through [qw(openssl rsautl -verify -pubin -inkey), $pub_key],
            $hash;

    seek $ko, 0, 0 or die "seek: $!";
    read $ko, my $d, (-s $ko) - $sig_len - 40 or die "read: $!";
    use Digest::SHA;
    my $fhash = new Digest::SHA($alg)->add($d)->digest;

    if($fhash eq $vhash){
        print "OK $kof\n";
    }else{
        print "**FAIL** $kof\n";
        $r = 1;
        warn 'orig=', unpack('H*', $vhash), "\n";
        warn 'file=', unpack('H*', $fhash), "\n";
    }
}
exit $r;

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

签名内核模块

来自分类Dev

如何用签名文件签名内核模块?

来自分类Dev

如何在Linux中禁用内核模块签名

来自分类Dev

如何为Android创建签名的可加载内核模块?

来自分类Dev

为SecureBoot签名iwlwifi内核模块

来自分类Dev

如何编译内核模块

来自分类Dev

更新后重新签名内核模块-VMMON

来自分类Dev

如何安装“ cdfs”内核模块?

来自分类Dev

如何临时禁用内核模块?

来自分类Dev

如何写入/ proc内核模块

来自分类Dev

如何从内核模块写入TTY?

来自分类Dev

如何从shell触发内核模块?

来自分类Dev

如何禁用内核模块中的缓存

来自分类Dev

如何调试插入的内核模块?

来自分类Dev

如何永久加载内核模块?

来自分类Dev

如何丢失树内内核模块?

来自分类Dev

如何临时禁用内核模块?

来自分类Dev

如何永久加载内核模块?

来自分类Dev

如何管理同名的多个内核模块?

来自分类Dev

如何永久禁用内核模块?

来自分类Dev

如何丢失树内内核模块?

来自分类Dev

如何从shell触发内核模块?

来自分类Dev

如何删除VirtualBox vboxdrv内核模块?

来自分类Dev

如何构建特定的内核模块?

来自分类Dev

如何监视“ iptables”内核模块的性能?

来自分类Dev

如何卸载正在使用的内核模块?

来自分类Dev

如何安装“cdfs”内核模块?

来自分类Dev

内核模块如何自动加载

来自分类Dev

测试内核模块