Help Center/ Server Migration Service/ FAQs/ Agent Installation and Startup/ How Do I Verify the Integrity of the Migration Agent Software Package?
Updated on 2026-03-19 GMT+08:00

How Do I Verify the Integrity of the Migration Agent Software Package?

You can follow the instructions below to verify the integrity of the migration Agent software package before installing it.

Windows Agent (Python 2)

  1. Log in to the source Windows server as Administrator.
  2. Download and install OpenSSL 3.2.6 or later.
  3. Download the root CA certificate Huawei Software Integrity Protection Root CA.der from the Huawei Cloud Support website to the source server.
  4. On the Agents page of the SMS console, click the download icons in the Windows Agent (Python 2) area to obtain the Agent software package, CMS file, and CRL file.

  5. Download the Agent installation program, CMS file, and CRL file to an empty directory (for example, C:\cmsVerify). Place the downloaded root CA certificate in this directory. Name the files exactly the same as those in the following figure.

  6. Create the C:\cmsVerify\verify.ps1 file and paste the following content to the file.

    $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. Open the PowerShell terminal and run the following script to verify the CMS signature. Replace the file directory and OpenSSL installation path with the actual ones.

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

  8. If "verify success!!!" is displayed in the last line, the signature passes the verification. Otherwise, the verification fails.

Windows Agent (Python 3)

  1. Log in to the source Windows server as the Administrator user.
  2. Download and install OpenSSL 3.2.6 or later.
  3. Download the root CA certificate Huawei Software Integrity Protection Root CA.der from the Huawei Cloud Support website to the source server.
  4. On the Agents page of the SMS console, click the download icons in the Windows Agent (Python 3) area to obtain the Agent software package, CMS file, and CRL file.

  5. Download the Agent installation program, CMS file, and CRL file to an empty directory (for example, C:\cmsVerify). Place the downloaded root CA certificate in this directory. Name the files exactly the same as those in the following figure.

  6. Create the C:\cmsVerify\verify.ps1 file and paste the following content to the file.

    $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. Open the PowerShell terminal and run the following script to verify the CMS signature. Replace the file directory and OpenSSL installation path with the actual ones.

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

  8. If "verify success!!!" is displayed in the last line, the signature passes the verification. Otherwise, the verification fails.

Linux

  1. Log in to the source Linux server as the root user.
  2. Download the root CA certificate Huawei Software Integrity Protection Root CA.der from the Huawei Cloud Support website to the source server.
  3. On the Agents page of the SMS console, click the copy icons in the Linux Agent area, and run those commands on the Linux server to obtain the Agent software package, CMS file, and CRL file.

  4. Download the Agent installation program, CMS file, and CRL file to an empty directory (for example, /tmp/cmsVerify). Place the downloaded root CA certificate in this directory. Name the files exactly the same as those in the following figure.

  5. Create the /tmp/cmsVerify/verify.sh file and paste the following content to the file.

    #!/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. Run the following script to verify the CMS signature. Replace the file directory with the actual one.

    cd /tmp/cmsVerify/
    chmod +x verify.sh
    /tmp/cmsVerify/verify.sh "/tmp/cmsVerify"

  7. If "verify success!!!" is displayed in the last line, the signature passes the verification. Otherwise, the verification fails.