更新时间:2025-12-05 GMT+08:00
如何校验迁移Agent软件包的完整性?
本节将为您介绍在安装迁移Agent前,如何对迁移Agent软件包进行完整性校验。
Windows Agent(Python2)
- 使用Administrator用户登录源端Windows主机。
- 下载并安装v3.2.6版本及以上的OpenSSL。
- 从华为云Support网站下载根CA证书(HuaweiSoftwareIntegrityProtectionRootCA.der)到源端主机。
- 在SMS控制台的迁移Agent页面,分别单击“Windows Agent(Python2)下载”框中的“链接”、“CMS链接”和“CRL链接”后的下载图标。

- 将迁移Agent安装程序、CMS和CRL文件下载到一个空目录下(例如:C:\cmsVerify)。同时,将下载的根CA证书也放置于该目录下。请注意,文件命名要和下图一致。

- 新建“C:\cmsVerify\verify.ps1”文件,并将以下内容复制到该文件中。
$workDir = $args[0] $opensslBinPath = $args[1] function ErrExit { param ( [string]$message ) if ([string]::IsNullOrEmpty($message)) { $message = "verify failed!!!" } Write-Host -ForegroundColor Red "[ERROR Line $($_.InvocationInfo.ScriptLineNumber)] $message" exit 1 } function CmsVerify { Write-Host "workDir: $workDir" Write-Host "opensslBinPath: $opensslBinPath" $packageName = "SMS-Agent-Py2.exe" $packageFilePath = Join-Path $workDir $packageName $cmsFilePath = "$packageFilePath.cms" $crlFilePath = "$packageFilePath.cms.crl" $rootCaFilePath = Join-Path $workDir "Huawei Software Integrity Protection Root CA.der" $opensslExePath = Join-Path $opensslBinPath "openssl.exe" $files = @($packageFilePath, $cmsFilePath, $crlFilePath, $rootCaFilePath, $opensslExePath) foreach ($file in $files) { if (-not (Test-Path -Path $file -PathType Leaf)) { ErrExit "File not found: $file" } } $tmpDir = "tmp_$(Get-Date -Format 'yyyyMMddHHmmss')" $script:fullTmpDir = Join-Path $workDir $tmpDir 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 } function Cleanup { if (Test-Path -Path $fullTmpDir -PathType Container -ErrorAction SilentlyContinue) { Remove-Item -Path $fullTmpDir -Recurse -Force } } function Main { try { CmsVerify if ($LASTEXITCODE -eq 0) { Write-Host "verify success!!!" -ForegroundColor Green } else { Write-Host "verify failed!!!" -ForegroundColor Red } } finally { Cleanup } } Register-EngineEvent PowerShell.Exiting -Action { Cleanup } trap { Write-Host "Error trapped: $($_.Exception.Message)" Write-Host "verify failed!!!" -ForegroundColor Red Cleanup exit 1 } Main - 打开PowerShell终端,执行如下脚本进行CMS验签。请注意,根据实际的文件目录和OpenSSL安装路径进行替换。
C:\cmsVerify\verify.ps1 "C:\cmsVerify" "C:\OpenSSL-Win64\bin"
- 如果最后一行输出“verify success!!!”则表示验签成功,否则验签失败。

Windows Agent(Python3)
- 使用Administrator用户登录源端Windows主机。
- 下载并安装v3.2.6版本及以上的OpenSSL。
- 从华为云Support网站下载根CA证书(HuaweiSoftwareIntegrityProtectionRootCA.der)到源端主机。
- 在SMS控制台的迁移Agent页面,分别单击“Windows Agent(Python3)下载”框中的“链接”、“CMS链接”和“CRL链接”后的下载图标。

- 将迁移Agent安装程序、CMS和CRL文件下载到一个空目录下(例如:C:\cmsVerify)。同时,将下载的根CA证书也放置于该目录下。请注意,文件命名要和下图一致。

- 新建“C:\cmsVerify\verify.ps1”文件,并将以下内容复制到该文件中。
$workDir = $args[0] $opensslBinPath = $args[1] function ErrExit { param ( [string]$message ) if ([string]::IsNullOrEmpty($message)) { $message = "verify failed!!!" } Write-Host -ForegroundColor Red "[ERROR Line $($_.InvocationInfo.ScriptLineNumber)] $message" exit 1 } function CmsVerify { Write-Host "workDir: $workDir" Write-Host "opensslBinPath: $opensslBinPath" $packageName = "SMS-Agent-Py3.exe" $packageFilePath = Join-Path $workDir $packageName $cmsFilePath = "$packageFilePath.cms" $crlFilePath = "$packageFilePath.cms.crl" $rootCaFilePath = Join-Path $workDir "Huawei Software Integrity Protection Root CA.der" $opensslExePath = Join-Path $opensslBinPath "openssl.exe" $files = @($packageFilePath, $cmsFilePath, $crlFilePath, $rootCaFilePath, $opensslExePath) foreach ($file in $files) { if (-not (Test-Path -Path $file -PathType Leaf)) { ErrExit "File not found: $file" } } $tmpDir = "tmp_$(Get-Date -Format 'yyyyMMddHHmmss')" $script:fullTmpDir = Join-Path $workDir $tmpDir 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 } function Cleanup { if (Test-Path -Path $fullTmpDir -PathType Container -ErrorAction SilentlyContinue) { Remove-Item -Path $fullTmpDir -Recurse -Force } } function Main { try { CmsVerify if ($LASTEXITCODE -eq 0) { Write-Host "verify success!!!" -ForegroundColor Green } else { Write-Host "verify failed!!!" -ForegroundColor Red } } finally { Cleanup } } Register-EngineEvent PowerShell.Exiting -Action { Cleanup } trap { Write-Host "Error trapped: $($_.Exception.Message)" Write-Host "verify failed!!!" -ForegroundColor Red Cleanup exit 1 } Main - 打开PowerShell终端,执行如下脚本进行CMS验签。请注意,根据实际的文件目录和OpenSSL安装路径进行替换。
C:\cmsVerify\verify.ps1 "C:\cmsVerify" "C:\OpenSSL-Win64\bin"
- 如果最后一行输出“verify success!!!”则表示验签成功,否则验签失败。

Linux版本
- 使用root用户登录源端Linux主机。
- 从华为云Support网站下载根CA证书(HuaweiSoftwareIntegrityProtectionRootCA.der)到源端主机。
- 在SMS控制台的迁移Agent页面,分别单击“Linux Agent 下载”框中的“下载Agent”、“下载CMS”和“下载CRL”后的复制图标,复制下载命令,在源端Linux主机执行命令下载。

- 将迁移Agent安装程序、CMS和CRL文件下载到一个空目录下(例如:/tmp/cmsVerify)。同时,将下载的根CA证书也放置于该目录下。请注意,文件命名要和下图一致。

- 新建“/tmp/cmsVerify/verify.sh”文件,并将以下内容复制到该文件中。
#!/bin/bash workDir=$1 err_exit() { local message="$1" if [ -z "$message" ]; then echo -e "\e[31m[ERROR Line ${BASH_LINENO[0]}] verify failed!!!\e[0m" else echo -e "\e[31m[ERROR Line ${BASH_LINENO[0]}] ${message}\e[0m" echo -e "\e[31mverify failed!!!\e[0m" fi exit 1 } cmsVerify() { packageName="SMS-Agent.tar.gz" packageFilePath=${workDir}/${packageName} cmsFilePath=${workDir}/${packageName}.cms crlFilePath=${workDir}/${packageName}.cms.crl rootCaFilePath=${workDir}/"Huawei Software Integrity Protection Root CA.der" files=("${packageFilePath}" "${cmsFilePath}" "${crlFilePath}" "${rootCaFilePath}") for file in "${files[@]}"; do if [ ! -f "$file" ]; then err_exit "File not found: ${file}" fi done tmpDir=tmp_$(date +"%Y%m%d%H%M%S") mkdir -p ${workDir}/${tmpDir} echo "tmpPath: ${workDir}/${tmpDir}" if ! command -v openssl &> /dev/null; then err_exit "openssl: command not found" fi # 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" || err_exit # 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 } cleanup() { if [ -d "${tmpDir}" ]; then rm -rf "${tmpDir}" fi } main() { cmsVerify if [ $? -eq 0 ]; then echo -e "\e[32mverify success!!!\e[0m" else echo -e "\e[31mverify failed!!!\e[0m" exit fi } trap cleanup EXIT INT TERM HUP main - 执行如下脚本进行CMS验签。请注意,根据实际的文件目录进行替换。
cd /tmp/cmsVerify/ chmod +x verify.sh /tmp/cmsVerify/verify.sh "/tmp/cmsVerify"
- 如果最后一行输出“verify success!!!”则表示验签成功,否则验签失败。
