
# 如何校验迁移Agent软件包的完整性？
本节将为您介绍在安装迁移Agent前，如何对迁移Agent软件包进行完整性校验。
#### Windows Agent(Python2)
1. 使用Administrator用户登录源端Windows主机。
2. 下载并安装v3.2.6版本及以上的OpenSSL。
3. 从华为云Support网站下载根CA证书（[HuaweiSoftwareIntegrityProtectionRootCA.der](https://download.huawei.com/dl/download.do?actionFlag=download&nid=PKI1000000015&partNo=3001&mid=SUP_PKI)）到源端主机。
4. 在SMS控制台的迁移Agent页面，分别单击"Windows Agent(Python2)下载"框中的"链接"、"CMS链接"和"CRL链接"后的下载图标。 
   ![](https://support.huaweicloud.com/sms_faq/zh-cn_image_0000002518152335.png "点击放大")
   
   
   
5. 将迁移Agent安装程序、CMS和CRL文件下载到一个空目录下（例如：C:\\cmsVerify）。同时，将下载的根CA证书也放置于该目录下。**请注意，文件命名要和下图一致** 。
   
   ![](https://support.huaweicloud.com/sms_faq/zh-cn_image_0000002518152245.png)
   
   
6. 新建"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
   ```
   
   
7. 打开PowerShell终端，执行如下脚本进行CMS验签。**请注意，根据实际的文件目录和OpenSSL安装路径进行替换** 。
   
   ```
   C:\cmsVerify\verify.ps1 "C:\cmsVerify" "C:\OpenSSL-Win64\bin"
   ```
   
   
8. 如果最后一行输出"verify success!!!"则表示验签成功，否则验签失败。 
   ![](https://support.huaweicloud.com/sms_faq/zh-cn_image_0000002486080554.png)
   
   
 
#### Windows Agent(Python3)
1. 使用Administrator用户登录源端Windows主机。
2. 下载并安装v3.2.6版本及以上的OpenSSL。
3. 从华为云Support网站下载根CA证书（[HuaweiSoftwareIntegrityProtectionRootCA.der](https://download.huawei.com/dl/download.do?actionFlag=download&nid=PKI1000000015&partNo=3001&mid=SUP_PKI)）到源端主机。
4. 在SMS控制台的迁移Agent页面，分别单击"Windows Agent(Python3)下载"框中的"链接"、"CMS链接"和"CRL链接"后的下载图标。 
   ![](https://support.huaweicloud.com/sms_faq/zh-cn_image_0000002518156871.png "点击放大")
   
   
   
5. 将迁移Agent安装程序、CMS和CRL文件下载到一个空目录下（例如：C:\\cmsVerify）。同时，将下载的根CA证书也放置于该目录下。**请注意，文件命名要和下图一致** 。
   
   ![](https://support.huaweicloud.com/sms_faq/zh-cn_image_0000002518157039.png)
   
   
6. 新建"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
   ```
   
   
7. 打开PowerShell终端，执行如下脚本进行CMS验签。**请注意，根据实际的文件目录和OpenSSL安装路径进行替换** 。
   
   ```
   C:\cmsVerify\verify.ps1 "C:\cmsVerify" "C:\OpenSSL-Win64\bin"
   ```
   
   
8. 如果最后一行输出"verify success!!!"则表示验签成功，否则验签失败。 
   ![](https://support.huaweicloud.com/sms_faq/zh-cn_image_0000002518120465.png)
   
   
 
#### Linux版本
1. 使用root用户登录源端Linux主机。
2. 从华为云Support网站下载根CA证书（[HuaweiSoftwareIntegrityProtectionRootCA.der](https://download.huawei.com/dl/download.do?actionFlag=download&nid=PKI1000000015&partNo=3001&mid=SUP_PKI)）到源端主机。
3. 在SMS控制台的迁移Agent页面，分别单击"Linux Agent 下载"框中的"下载Agent"、"下载CMS"和"下载CRL"后的复制图标，复制下载命令，在源端Linux主机执行命令下载。 
   ![](https://support.huaweicloud.com/sms_faq/zh-cn_image_0000002518158403.png "点击放大")
   
   
   
4. 将迁移Agent安装程序、CMS和CRL文件下载到一个空目录下（例如：/tmp/cmsVerify）。同时，将下载的根CA证书也放置于该目录下。**请注意，文件命名要和下图一致** 。
   
   ![](https://support.huaweicloud.com/sms_faq/zh-cn_image_0000002518118545.png)
   
   
5. 新建"/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
   ```
   
   
6. 执行如下脚本进行CMS验签。**请注意，根据实际的文件目录进行替换** 。
   
   ```
   cd /tmp/cmsVerify/
   chmod +x verify.sh
   /tmp/cmsVerify/verify.sh "/tmp/cmsVerify"
   ```
   
   
7. 如果最后一行输出"verify success!!!"则表示验签成功，否则验签失败。 
   ![](https://support.huaweicloud.com/sms_faq/zh-cn_image_0000002485920590.png)
   
   
 
