安全研究

安全漏洞
OpenCA多个签名验证漏洞

发布日期:2003-11-28
更新日期:2003-12-03

受影响系统:
OpenCA OpenCA 0.9.1-3
OpenCA OpenCA 0.9.1-2
OpenCA OpenCA 0.9.1-1
OpenCA OpenCA 0.9.1
OpenCA OpenCA 0.9.0-2
OpenCA OpenCA 0.9.0-1
OpenCA OpenCA 0.9.0
OpenCA OpenCA 0.8.6
OpenCA OpenCA 0.8.1
OpenCA OpenCA 0.8.0
不受影响系统:
OpenCA OpenCA 0.9.1-4
描述:
BUGTRAQ  ID: 9123
CVE(CAN) ID: CVE-2003-0960

OpenCA是一款提供PKI架构和相关项目开发的项目实现。

OpenCA存在多个漏洞,可导致修改的或过期的证书被接受。

具体问题如下:

1、OpenCA有一个通用加密操作的库-crypto-utils.lib,这个库包含一个函数判断用于建立PKCS#7签名的证书序列,函数使用这个序列装载和返回证书。不过这个函数错误的使用OpenCA::PKCS7接口。

2、加密库crypto-utils.lib使用所有包含签名的证书来建议签名者证书的X.509对象,结果是来自证书链之一的证书建立的对象可以是任意的。

3、OpenCA::PKCS7包含一个错误规则表达式用于判断证书链的解析。

4、在OpenCA::PKCS7中证书链中的序列被错误的规则表达式解析,一些大写字符如A,C,B,D,E和F会被忽略。

<*来源:OpenCA Security Advisory
  
  链接:http://www.openca.org/news/CAN-2003-0960.txt
*>

建议:
临时解决方法:

如果您不能立刻安装补丁或者升级,NSFOCUS建议您采取以下措施以降低威胁:

--- openca-0.9.1.3/src/modules/openca-pkcs7/PKCS7.pm    2002-09-10 16:42:02.000000000 +0200
+++ openca-0.9.1.4/src/modules/openca-pkcs7/PKCS7.pm    2003-11-26 15:54:08.000000000 +0100
@@ -69,7 +69,7 @@

our ($errno, $errval);

-($OpenCA::PKCS7::VERSION = '$Revision: 1.12 $' )=~ s/(?:^.*: (\d+))|(?:\s+\$$)/defined $1?"0\.9":""/eg;
+($OpenCA::PKCS7::VERSION = '$Revision: 1.12.2.1 $' )=~ s/(?:^.*: (\d+))|(?:\s+\$$)/defined $1?"0\.9":""/eg;

my %params = (
     inFile => undef,
@@ -167,6 +167,8 @@

    my ( $ret, $tmp );

+    return $self->{parsed} if ($self->{parsed});
+
    $tmp = $self->{backend}->verify( SIGNATURE=>$self->{signature},
            DATA_FILE=>$self->{dataFile},
            CA_CERT=>$self->{caCert},
@@ -292,10 +294,10 @@
            ($self->{status}) = ( $line =~ /^\s*error:([^:]*):/ );
        }

-        next if( $line != /^depth/i );
+        next if( $line !~ /^depth/i );

        ( $currentDepth, $serial, $dn ) =
-            ( $line =~ /depth:([\d]+) serial:([a-f\d]+) subject:(.*)/ );
+            ( $line =~ /depth:([\d]+) serial:([a-fA-F\d]+) subject:(.*)/ );
        $ret->{$currentDepth}->{SERIAL} = hex ($serial) ;
        $ret->{$currentDepth}->{DN} = $dn;

--- openca-0.9.1.3/src/common/lib/functions/crypto-utils.lib    2002-12-22 13:08:19.000000000 +0100
+++ openca-0.9.1.4/src/common/lib/functions/crypto-utils.lib    2003-11-26 13:04:50.000000000 +0100
@@ -176,19 +176,36 @@
        return undef;
    }

-    ## Get signer certificate from the pkcs7 structure
-    $sigCert = new OpenCA::X509 ( SHELL => $cryptoShell,
-            DATA => $sig->getSigner()->{CERTIFICATE});
-
-    if( not $sigCert ) {
-        $errno    = 6103;
-        $errval    = i18nGettext ("Signer's certificate is corrupt!\nOpenCA::X509 returns errorcode __ERRNO__ (__ERRVAL__).",
-                               "__ERRNO__", $OpenCA::X509::errno,
-                               "__ERRVAL__", $OpenCA::X509::errval);
-        return undef;
+    ## Get signer certificate chain from the pkcs7 structure
+    my @chain = split /-----END CERTIFICATE-----/,
+                $sig->getSigner()->{CERTIFICATE};
+    for (my $i=0; $i < scalar @chain; $i++)
+    {
+        if (not $chain[$i])
+        {
+            delete $chain[$i];
+            next;
+        }
+        $chain[$i] .= "-----END CERTIFICATE-----";
+        $chain[$i] =~ s/^.*-----BEGIN CERTIFICATE-----/-----BEGIN CERTIFICATE-----/s;
+    }
+    $sigCert = undef;
+    for (my $i=0; $i < scalar @chain; $i++)
+    {
+        $sigCert = new OpenCA::X509 ( SHELL => $cryptoShell,
+                DATA => $chain[$i]);
+        if( not $sigCert ) {
+            $errno    = 6103;
+            $errval    = i18nGettext ("Signer's certificate is corrupt!\nOpenCA::X509 returns errorcode __ERRNO__ (__ERRVAL__).",
+                                   "__ERRNO__", $OpenCA::X509::errno,
+                                   "__ERRVAL__", $OpenCA::X509::errval);
+            return undef;
+        }
+        last if ( $tmpCert->getSerial() eq $sigCert->getSerial() );
+        $sigCert = undef;
    }

-    if( $tmpCert->getSerial() ne $sigCert->getSerial() ) {
+    if( not $sigCert ) {
        $errno    = 6104;
        $errval    = gettext ("Signer's Certificate and DB's Certificate do not match");
        return undef;
@@ -281,19 +298,8 @@
        return undef;
    }

-    my $sigCert = new OpenCA::X509 ( SHELL => $cryptoShell,
-                                     DATA => $sig->getSigner()->{CERTIFICATE});
-
-    if (not $sigCert) {
-        $errno    = 6302;
-        $errval    = i18nGettext ("Cannot create X509-object from the certificate of the signer! OpenCA::X509 returns errorcode __ERRNO__ (__ERRVAL__).",
-                               "__ERRNO__", $OpenCA::X509::errno,
-                               "__ERRVAL__", $OpenCA::X509::errval);
-        return undef;
-    }
-
    my $db_cert = $db->getItem( DATATYPE => 'CERTIFICATE',
-                KEY => $sigCert->getSerial() );
+                KEY => $sig->getSigner()->{SERIAL} );

    if( not $db_cert ) {
        $errno    = 6303;

--- openca-0.9.1.3/src/common/lib/cmds/verifySignature    2003-03-31 15:45:19.000000000 +0200
+++ openca-0.9.1.4/src/common/lib/cmds/verifySignature    2003-11-26 13:04:34.000000000 +0100
@@ -11,7 +11,7 @@
## Get the Configuration parameters ...
my ( $parsed, $lnk, $serLink, $sigInfo, $sigStatus, $signer, $signature);
my ( $baseDoc, $info, $sigCertStatus, $def, $dbStatus, $dbMessage);
-my ( $myCN, $myEmail, $mySerial, @sigCert, $tmpCert, $pCert );
+my ( $myCN, $myEmail, $mySerial, $tmpCert, $pCert );

## Get Required Parameters from Configuration
my $baseDoc    = getRequired ('verifySignatureform');
@@ -53,10 +53,7 @@
$myDN = $signer->{DN};
$myDN =~ s/^\///; $myDN =~ s/\//<BR>/g;

-$sigCert = new OpenCA::X509 ( SHELL => $cryptoShell,
-                  DATA => $sign->getSigner()->{CERTIFICATE});
-
-$issuerDN = $sigCert->getParsed()->{ISSUER};
+$issuerDN = $sign->getParsed()->{CHAIN}->{1}->{DN};
$issuerDN =~ s/^\///; $issuerDN =~ s/[\/\,]/<BR>/g;

## Check Signature Status
@@ -71,7 +68,7 @@
        $dbStatus = $errno;
        $sigStatus = "<FONT COLOR=\"Red\">".gettext("Unknown")."</FONT>";

-        $serLink = $sigCert->getSerial();
+        $serLink = $sign->getSigner()->{SERIAL};
    } else {
        $sigMessage = gettext("Signature correctly verified");
    }
@@ -96,11 +93,7 @@
    $serLink    = $tmpCert->getSerial();
}

-if( $sigCert ) {
-    $pCert = $sigCert->getParsed();
-} elsif ( $tmpCert ) {
-    $pCert = $tmpCert->getParsed();
-}
+$pCert = $tmpCert->getParsed();

## View the Operator Used Certificate Data
$page = $query->subVar( $page, '@DN@',       ($myDN or "n/a" ) );

--- openca-0.9.1.3/src/common/lib/cmds/viewSignature    2002-12-10 16:18:15.000000000 +0100
+++ openca-0.9.1.4/src/common/lib/cmds/viewSignature    2003-11-26 13:04:34.000000000 +0100
@@ -11,7 +11,7 @@
## Get the Configuration parameters ...
my ( $parsed, $lnk, $serLink, $sigInfo, $sigStatus, $signer, $signature);
my ( $baseDoc, $info, $sigCertStatus, $def, $dbStatus, $dbMessage);
-my ( $myCN, $myEmail, $mySerial, @sigCert, $tmpCert, $pCert );
+my ( $myCN, $myEmail, $mySerial, $tmpCert, $pCert );

my $dataType     = $query->param('dataType' );
my $key          = $query->param('key');
@@ -54,9 +54,6 @@
        name=>"EMAIL", value=>$signer->{DN_HASH}->{EMAILADDRESS}[0]} );
$myEmail = $lnk->a({-href=>$lnk->self_url()}, $signer->{DN_HASH}->{EMAILADDRESS}[0]);

-$sigCert = new OpenCA::X509 ( SHELL => $cryptoShell,
-                  DATA => $signature->getSigner()->{CERTIFICATE});
-
## Check Signature Status
if( not libCheckSignature( SIGNATURE=>$signature ) ) {
    $sigStatus = "<FONT COLOR=\"Red\">".gettext("Error")."</FONT>";
@@ -105,7 +102,7 @@
    $serLink = $lnk->a({-href=>$lnk->self_url()},
            $tmpCert->getSerial() );

-     $decSerLink = "( " . hex( $sigCert->getSerial() ) . " )";
+     $decSerLink = "( " . hex( $tmpCert->getSerial() ) . " )";

     $lnk = new CGI({cmd      => "search",
                     dataType => "CERTIFICATE",
@@ -114,11 +111,7 @@
     $myEmail = $lnk->a({-href=>$lnk->self_url()}, $tmpCert->getParsed()->{EMAILADDRESS});
}

-if( $sigCert ) {
-    $pCert = $sigCert->getParsed();
-} elsif ( $tmpCert ) {
-    $pCert = $tmpCert->getParsed();
-}
+$pCert = $tmpCert->getParsed();

## View the Operator Used Certificate Data
$page = $query->subVar( $page, '@CN@',       ($myCN or "n/a" ) );

厂商补丁:

OpenCA
------
目前厂商已经发布了升级补丁以修复这个安全问题,请到厂商的主页下载:

OpenCA Upgrade openca-0.9.1-4.tar.gz
http://www.openca.org/cgi-bin/openca/downloads/sf-dl?name=openca-0.9.1-4.tar.gz

浏览次数:3673
严重程度:0(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障