¿Cómo firmar un script de PowerShell (PS1) con un certificado de firma de código?

Un script o un ejecutable con firma digital permite al usuario asegurarse de que un archivo es original y su código no ha sido modificado por terceros. Las versiones actuales de PowerShell tienen herramientas integradas para la firma de código de archivos de script *.ps1 mediante certificados digitales.

Puede firmar un script de PowerShell utilizando un tipo especial de certificado: Firma de código. Este certificado se puede obtener de una autoridad de certificación (AC) comercial externa, una CA empresarial interna o puede usar un certificado autofirmado.

Suponga que los servicios PKI (Servicios de certificados de Active Directory) se implementan en su dominio. Solicitemos un nuevo certificado yendo a https://nombre-servidor-CA/certsrv y solicitar un nuevo certificado con el Firma de código plantilla (esta plantilla debe habilitarse primero en la consola de la Autoridad de Certificación).

empresa ca: cree un certificado a partir de una plantilla de firma de código

Además, el usuario puede solicitar un certificado para firmar scripts de PowerShell desde el complemento mmc Certificados -> Mi cuenta -> Personal -> Todas las tareas -> Solicitar un nuevo certificado.

Solicite un nuevo certificado de firma de código de certificado en Windows 10

Si solicitó manualmente un certificado, debe tener un archivo de certificado x509 con un .cer extensión. Este certificado debe estar instalado en el almacén de certificados local de su computadora.

Puede usar los siguientes comandos de PowerShell para agregar el certificado a los certificados raíz de confianza de la computadora:

$certFile = Export-Certificate -Cert $cert -FilePath C:pscertname.cer
Import-Certificate -CertStoreLocation Cert:LocalMachineAuthRoot -FilePath $certFile.FullName

Si desea usar un certificado autofirmado, use el cmdlet New-SelfSignedCertificate para crear un certificado CodeSigning con el nombre DNS testPC1:

New-SelfSignedCertificate -DnsName testPC1 -Type CodeSigning
$cert = New-SelfSignedCertificate -Subject "Cert for Code Signing” -Type CodeSigningCert -DnsName test1 -CertStoreLocation cert:LocalMachineMy

Una vez generado el certificado, muévalo del contenedor intermedio a la raíz de confianza mediante la consola del Administrador de certificados (certmgr.msc).

Después de obtener el certificado, puede configurar la política de ejecución de scripts de PowerShell para permitir que solo se ejecuten los scripts firmados. De forma predeterminada, la política de ejecución de PowerShell en Windows 10/Windows Server 2016 está configurada en Restringido (bloquea la ejecución de cualquier script de PowerShell).

File C:psscript.ps1 cannot be loaded because running scripts is disabled on this system.

Para permitir que solo se ejecuten los scripts de PS1 firmados, puede cambiar la Política de ejecución de PowerShell a AllSigned o RemoteSigned (con la única diferencia de que RemoteSigned requiere una firma solo para los scripts descargados de Internet):

Set-ExecutionPolicy AllSigned –Force

En este modo, al ejecutar scripts de PowerShell sin firmar, aparece un error:

File C:script.ps1 cannot be loaded. The file script.ps1 is not digitally signed. You cannot run this script on the current system.

También puede permitir que se ejecuten scripts de PowerShell firmados mediante el Activar la ejecución de secuencias de comandos Parámetro de directiva de grupo en Configuración del equipo -> Políticas -> Plantillas administrativas -> Componentes de Windows -> Windows PowerShell. Cambie el valor del parámetro a Permitir solo scripts firmados.

Ahora pasemos a firmar el archivo de script de PowerShell. En primer lugar, debe obtener el certificado de CodeSign del almacén de certificados local del usuario actual. Primero, enumeremos todos los certificados que se pueden usar para firmar código:

Get-ChildItem cert:CurrentUsermy –CodeSigningCert

En nuestro caso, tomaremos el primer certificado del almacén de certificados de usuario personal y lo guardaremos en la variable $cert:

$cert = (Get-ChildItem cert:CurrentUsermy –CodeSigningCert)[0]

Si movió su certificado al almacén de certificados raíz de confianza, use el siguiente comando:

$cert = (Get-ChildItem Cert:LocalMachineAuthRoot –CodeSigningCert)[0]

Luego puede usar este certificado para firmar el archivo PS1 con su script de PowerShell:

Set-AuthenticodeSignature -Certificate $cert -FilePath C:PStestscript.ps1

También puede usar el siguiente comando (en este caso, seleccionamos el certificado autofirmado creado anteriormente por DnsName):

Set-AuthenticodeSignature C:PStest_script.ps1 @(gci Cert:LocalMachineAuthRoot -DnsName testPC1 -codesigning)[0]

Insinuación. El cmdlet Set-AuthenticodeSignature tiene un parámetro especial TimestampServer que especifica la URL para la marca de tiempo del servicio. Si este parámetro se deja en blanco, el script de PS dejará de ejecutarse después de que caduque el certificado. Por ejemplo, puede configurar un servidor de marca de tiempo de la siguiente manera: -TimestampServer "http://timestamp.verisign.com/scripts/timstamp.dll"

Si intenta utilizar un certificado SSL/TLS común para firmar el script, aparece un error:

Set-AuthenticodeSignature: Cannot sign code. The specified certificate is not suitable for code signing.

Puede firmar todos los archivos de script de PowerShell a la vez en la carpeta:

Get-ChildItem c:ps*.ps1| Set-AuthenticodeSignature -Certificate $Cert

Ahora puede verificar que el archivo de script de PowerShell esté firmado correctamente. Puede usar el cmdlet Get-AuthenticodeSignature o abrir las propiedades del archivo PS1 e ir a la Firmas digitales pestaña.

Get-AuthenticodeSignature c:pstest_script.ps1 | ft -AutoSize

Get-AuthenticodeSignature verifique la firma de un script de PowerShell firmado

Si una UnknownError aparece una advertencia al ejecutar el comando Set-AuthenticodeSignature, entonces este certificado no es de confianza porque se encuentra en el almacén de certificados personales del usuario.

Establecer-AuthenticodeSignature UnknownError

Debe moverlo a Certificados raíz de confianza (no olvide comprobar periódicamente el almacén de certificados de Windows en busca de certificados sospechosos y actualizar las listas de certificados raíz de confianza):

Move-Item -Path $cert.PSPath -Destination "Cert:LocalMachineRoot"

Ahora, al verificar la firma de un archivo PS1, se debe devolver el estado Válido.

PowerShell mueve el certificado a la raíz de confianza

Al firmar un archivo de script de PowerShell, el cmdlet Set-AuthenticodeSignature agrega un bloque de firma digital al final del archivo de texto de PS1:

# SIG # Begin signature block
...........
...........
# SIG # End signature block

bloque de firma en el archivo de script de PowerShell

El bloque de firma contiene el hash del script, que se cifra con la clave privada.

La primera vez que intente ejecutar el script, aparecerá una advertencia:

Do you want to run software from this untrusted publisher?
File C:PSscript.ps1 is published by CN=testPC1 and is not trusted on your system. Only run scripts from trusted publishers.

Si selecciona [A] Ejecutar siempre en la primera ejecución del script, la próxima vez que ejecute el script, firmado con este certificado, ya no aparecerá una advertencia.

El archivo ps1 es publicado por CN= y no es de confianza en su sistema. Solo ejecute scripts de editores de confianza.

Para evitar que aparezca esta advertencia, debe copiar el certificado también en el Editores de confianza Autoridad certificada. Utilice la operación Copiar y Pegar en la consola Certificados para copiar el certificado en Editores de confianza -> Certificados.

copiar el certificado de firma de código a los editores de confianza

El script de PowerShell firmado ahora se ejecutará sin mostrar una notificación de editor que no sea de confianza.

Consejo. El certificado raíz de CA y el certificado utilizado para firmar el script deben ser de confianza (de lo contrario, el script no se ejecutará). Puede implementar certificados de forma centralizada en equipos de dominio mediante GPO. Los certificados deben colocarse en las siguientes secciones de clave pública de GPO: Configuración de la computadora -> Políticas -> Configuración de Windows -> Configuración de seguridad -> Políticas de clave pública -> Autoridades de certificación raíz de confianza y Editores de confianza.

Si el certificado raíz no es de confianza, cuando ejecute el script de PowerShell, aparecerá un error:

A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.

¿Qué sucederá si cambia el código del archivo de script de PowerShell firmado? El intento de ejecutarlo se bloqueará con la notificación de que se ha cambiado el contenido del script.

File xx.ps1 cannot be loaded. The contents of file xx.ps1 might  have been changed by an unauthorized user or process, because the hash of the file does not match the hash stored in the digital signature. The script cannot run on the specified system.

Se ha cambiado el contenido del archivo de script de PowerShell. el hash del archivo no coincide con el hash almacenado en la firma digital

Intente verificar la firma del script mediante el cmdlet Get-AuthenticodeSignature. Si el hash calculado no coincide con el hash de la firma, el mensaje HashMismatch aparece

Obtener AuthenticodeSignature HashMismatch

Por lo tanto, cualquier modificación del código del script de PS1 firmado requerirá volver a firmarlo.

Artículos Interesantes