更新时间:2025-12-01 GMT+08:00

校验MgC Agent软件包完整性

本节将为您介绍在安装MgC Agent前,如何对MgC Agent软件包的数字签名CMS进行完整性校验。

Windows版本

  1. 使用Administrator用户登录用于安装MgC Agent的Windows主机。
  2. 下载并安装v3.2.6版本及以上的OpenSSL。
  3. 从华为云Support网站下载根CA证书(HuaweiSoftwareIntegrityProtectionRootCA.der)到本地。
  4. 在MgC控制台的迁移中心Agent页面,分别单击“应用迁移(手动安装)”框中的“下载 >下载Windows安装包”和“下载 >下载Windows CMS和CRL”。将MgC Agent安装程序、CMS和CRL文件下载到一个空目录下(例如:C:\cmsVerify)。请注意,文件命名要和下图一致

  5. 新建“C:\cmsVerify\verify.ps1”文件,并将以下内容复制到该文件中。

    $workDir = $args[0] 
    $opensslBinPath = $args[1] 
    
    function cmsVerify { 
    	Write-Host "workDir: $workDir" 
    	Write-Host "opensslBinPath: $opensslBinPath" 
    	$packageName="MgC-Agent.zip" 
    	$packageFilePath = Join-Path $workDir $packageName 
    	$cmsFilePath = "$packageFilePath.cms" 
    	$crlFilePath = "$packageFilePath.cms.crl" 
    	$rootCaFilePath = Join-Path $workDir "Huawei Software Integrity Protection Root CA.der" 
    	$tmpDir = "tmp_$(Get-Date -Format 'yyyyMMddHHmmss')" 
    	$fullTmpDir = Join-Path $workDir $tmpDir 
    	$opensslExePath = Join-Path $opensslBinPath "openssl.exe" 
    	New-Item -ItemType Directory -Path $fullTmpDir -Force | Out-Null 
    	Write-Host "tmpPath: $fullTmpDir" 
    
    	# get sign time 
    	$asnOutput = & "$opensslExePath" asn1parse -inform DER -in $cmsFilePath 
    	$signingTimeLineNum = $asnOutput | Out-String -Stream | Select-String -Pattern ":signingTime" | Select-Object -Skip 1 -First 1 | ForEach-Object { $_.LineNumber } 
    	$timeLineNum = $signingTimeLineNum + 2 
    	$originalTimeStr = ((($asnOutput | Select-Object -Index ($timeLineNum - 1))  -replace '\s+', '') -split ':UTCTIME:' ) | Select-Object -Skip 1 -First 1 
    	$timeStr = $originalTimeStr.Trim() 
    	$year = "20" + $timeStr.Substring(0, 2) 
    	$month = $timeStr.Substring(2, 2) 
    	$day = $timeStr.Substring(4, 2) 
    	$hour = $timeStr.Substring(6, 2) 
    	$minute = $timeStr.Substring(8, 2) 
    	$second = $timeStr.Substring(10, 2) 
    	$dateTime = New-Object DateTime ($year, $month, $day, $hour, $minute, $second) 
    	$signTimestap = [int][double]::Parse((Get-Date $dateTime -UFormat "%s")) 
    	Write-Host "signTimestap: $signTimestap" 
    
    	# split the CRL file and obtain all revocation lists 
    	Write-Host "start handle crl file" 
    	$asn1ParseResult = & "$opensslExePath" asn1parse -in $crlFilePath -inform DER 
    	$handledLen = 0 
    	$crlPemPath = Join-Path $fullTmpDir "crl.pem" 
    	New-Item -Path $crlPemPath -ItemType File -Force | Out-Null 
    	for ($i = 1; $i -le 1000; $i++) { 
    		$fileHead = $asn1ParseResult | Select-String -Pattern "^\s*${handledLen}:d=.*" 
    		if (-not $fileHead) { 
    			Write-Host "crl file is end" 
    			break 
    		} 
    		Write-Host "find file head info: $fileHead" 
    		$headLen = [regex]::Match($fileHead, 'hl=(\d+)').Groups[1].Value 
    		$contLen = [regex]::Match($fileHead, '(?<!h)l=\s*(\d+)').Groups[1].Value 
    		$headLen = [int]$headLen 
    		$contLen = [int]$contLen 
    		$totalLen = $headLen + $contLen 
    		# extract CRL fragment 
    		$tmpCrlPath = Join-Path $fullTmpDir "tmp.crl" 
    		$buffer = [System.IO.File]::ReadAllBytes($crlFilePath) 
    		$segment = $buffer[$handledLen..($handledLen + $totalLen - 1)] 
    		[System.IO.File]::WriteAllBytes($tmpCrlPath, $segment) 
    		# attempt to convert to PEM format 
    		& "$opensslExePath" crl -inform DER -in $tmpCrlPath -outform PEM -out "$fullTmpDir\tmp.pem" 2>$null 
    		if ($LASTEXITCODE -eq 0) { 
    			Get-Content "$fullTmpDir\tmp.pem" | Add-Content $crlPemPath 
    			Write-Host "convert to crl pem success!" 
    		} else { 
    			Write-Host "not crl format" 
    		} 
    		$handledLen += $totalLen 
    	} 
    	Write-Host "handle crl file finish" 
    
    	# convert root CA format to CER 
    	$rootCaCerPath = Join-Path $fullTmpDir "rootCa.cer" 
    	& "$opensslExePath" x509 -inform der -in $rootCaFilePath -out $rootCaCerPath 
    
    	# verify the integrity of the software package and obtain the certificate chain 
    	Write-Host "start verify cms" 
    	$cmsVerifiedData = Join-Path $fullTmpDir "cmsVerifiedData" 
    	$cmsCertChain = Join-Path $fullTmpDir "cmsCertChain.pem" 
    	& "$opensslExePath" cms -verify -attime $signTimestap -inform DER -in $cmsFilePath -content $packageFilePath -CAfile $rootCaCerPath -out $cmsVerifiedData -binary -purpose any -certsout $cmsCertChain 
    	if ($LASTEXITCODE -eq 0) { 
    		Write-Host "verify cms success!!!" 
    	} else { 
    		Write-Host "verify cms failed!!!" 
    		return 1 
    	} 
    
    	# verify the validity of the certificate chain 
    	Write-Host "start verify cert chain" 
    	& "$opensslExePath" verify -attime $signTimestap -crl_check -CAfile $rootCaCerPath -untrusted $cmsCertChain -CRLfile $crlPemPath $cmsCertChain 
    	if ($LASTEXITCODE -eq 0) { 
    		Write-Host "verify cert chain success!!!" 
    	} else { 
    		Write-Host "verify cert chain failed!!!" 
    		return 1 
    	} 
        return 0 
    } 
    
    cmsVerify 
    if ($LASTEXITCODE -eq 0) { 
        Write-Host "verify success!!!" -ForegroundColor Green 
    } else { 
        Write-Host "verify failed!!!" -ForegroundColor Red 
    }

  6. 打开PowerShell终端,执行如下脚本进行CMS验签。请注意,根据实际的文件目录和OpenSSL安装路径进行替换

    C:\cmsVerify\verify.ps1 "C:\cmsVerify" "C:\OpenSSL-Win64\bin"

  7. 如果最后一行输出“verify success!!!”则表示验签成功,否则验签失败。

Linux版本

  1. 使用root用户登录用于安装MgC Agent的Linux主机。
  2. 从华为云Support网站下载根CA证书(HuaweiSoftwareIntegrityProtectionRootCA.der)到本地。
  3. 在MgC控制台的迁移中心Agent页面,分别单击“应用迁移(手动安装)”框中的“下载 >下载Linux安装包”和“下载 >下载Linux CMS和CRL”,将MgC Agent安装程序、CMS和CRL文件下载到一个空目录下(例如:/tmp/cmsVerify)。请注意,文件命名要和下图一致

  4. 新建“/tmp/cmsVerify/verify.sh”文件,并将以下内容复制到该文件中。

    workDir=$1
    
    function cmsVerify() {
    	packageName="MgC-Agent.tar.gz"
    	packageFilePath=${workDir}/${packageName}
    	cmsFilePath=${workDir}/${packageName}.cms
    	crlFilePath=${workDir}/${packageName}.cms.crl
    	rootCaFilePath=${workDir}/"Huawei Software Integrity Protection Root CA.der"
    	tmpDir=tmp_$(date +"%Y%m%d%H%M%S")
    	mkdir -p ${workDir}/${tmpDir}
    
    	echo "tmpPath: ${workDir}/${tmpDir}"
    
    	# get sign time
    	lineNum=`openssl asn1parse -inform DER -in ${cmsFilePath} | grep -n ':signingTime' | sed -n '2p' | cut -d: -f1`
    	echo "lineNum: ${lineNum}"
    	timeLineNum=$(($lineNum+2))
    	timeLine=`openssl asn1parse -inform DER -in ${cmsFilePath} | sed -n "${timeLineNum}p" | awk -F ':' '{print $4}'`
    	signTimestap=`date -d "20${timeLine:0:2}-${timeLine:2:2}-${timeLine:4:2} ${timeLine:6:2}:${timeLine:8:2}:${timeLine:10:2} UTC" +%s`
    	echo "signTimestap: ${timeLine} ${signTimestap}"
    	# split the CRL file and obtain all revocation lists
    	handledLen=0
    	echo "start handle crl file"
    	asn1ParseResult=`openssl asn1parse -in ${crlFilePath} -inform DER`
    	for i in {1..1000}
    	do
    		fileHead=`printf "%s" "${asn1ParseResult}" | grep "^[[:space:]]*${handledLen}:d=" | xargs`
    		if [[ -z "$fileHead" ]]; then
    			echo "crl file is end"
    			break;
    		fi
    		echo "find file head info: ${fileHead}"
    		headLen=`echo ${fileHead} | awk -F '=' '{print $3}' | grep -oP '[0-9]+'`
    		contLen=`echo ${fileHead} | awk -F '=' '{print $4}' | grep -oP '[0-9]+'`
    		totalLen=$(($headLen+$contLen))
    		# extract CRL fragment
    		dd if=${crlFilePath} status=none bs=1 skip=${handledLen} count=${totalLen} | openssl crl -inform DER -outform PEM -out ${workDir}/${tmpDir}/tmp.pem > /dev/null 2>&1
    		if [ $? -eq 0 ]; then
    			cat ${workDir}/${tmpDir}/tmp.pem >> ${workDir}/${tmpDir}/crl.pem
    			echo "convert to crl pem success!"
    		else
    			echo "not crl format"
    		fi
    		handledLen=$(($totalLen+$handledLen))
    	done
    	echo "handle crl file finish"
    
    	# convert root CA format to CER
    	openssl x509 -inform der -in "${rootCaFilePath}" -out "${workDir}/${tmpDir}/rootCa.cer"
    
    	# verify the integrity of the software package and obtain the certificate chain
    	echo "start verify cms"
    	openssl cms  -verify -attime ${signTimestap} -inform DER  -in ${cmsFilePath}  -content ${packageFilePath}  -CAfile "${workDir}/${tmpDir}/rootCa.cer"  -out "${workDir}/${tmpDir}/cmsVerifiedData" -binary -purpose any  -certsout "${workDir}/${tmpDir}/cmsCertChain.pem"
    	if [ $? -eq 0 ]; then
    		echo "verify cms success!!!"
    	else
    		echo "verify cms failed!!!"
    		return 103
    	fi
    
    
    	# verify the validity of the certificate chain
    	echo "start verify cert chain"
    	openssl verify -attime ${signTimestap} -crl_check -CAfile "${workDir}/${tmpDir}/rootCa.cer" -untrusted "${workDir}/${tmpDir}/cmsCertChain.pem" -CRLfile "${workDir}/${tmpDir}/crl.pem" "${workDir}/${tmpDir}/cmsCertChain.pem"
    	if [ $? -eq 0 ]; then
    		echo "verify cert chain success!!!"
    	else
    		echo "verify cert chain failed!!!"
    		return 104
    	fi
    	return 0
    }
    
    cmsVerify
    if [ $? -eq 0 ]; then
    	echo -e "\e[32mverify success!!!\e[0m"
    else
    	echo -e "\e[31mverify failed!!!\e[0m"
    	exit
    fi

  5. 执行如下脚本进行CMS验签。请注意,根据实际的文件目录进行替换

    sh /tmp/cmsVerify/verify.sh "/tmp/cmsVerify"

  6. 如果最后一行输出“verify success!!!”则表示验签成功,否则验签失败。