Firma de código
La firma de código es una parte esencial de la distribución de aplicaciones. En Windows, es probable que las aplicaciones sin firma de código se marquen como virus. En OSX, la firma de código y la notarización son obligatorias para que los usuarios puedan ejecutar tu aplicación.
En ambas plataformas, la firma debe realizarla el propio Velopack, ya que los binarios de Velopack (como Update y Setup) deben firmarse en distintos momentos del proceso de compilación del paquete.
SmartScreen y antivirus
En Windows, SmartScreen y el software antivirus marcan con frecuencia las aplicaciones sin firmar, y los usuarios pueden ver una advertencia antes de poder ejecutar tu aplicación. La forma más fiable de evitarlo es firmar el código de tu aplicación (ver más abajo), pero la firma por sí sola no siempre tiene un efecto inmediato: las advertencias de SmartScreen se basan en la reputación, que se acumula con el tiempo a medida que más usuarios ejecutan tus binarios firmados.
Esta es la regla general para las advertencias de Windows Defender / SmartScreen:
- No firmas tu código. Publicas MyApp-v1.exe. Los usuarios reciben advertencias de SmartScreen durante un tiempo, hasta que aumenta la reputación de ese archivo. Publicas MyApp-v2.exe. Los usuarios vuelven a recibir advertencias hasta que MyApp-v2.exe acumula suficiente reputación.
- Firmas tu código con un certificado OV. Publicas MyApp-v1.exe. Los usuarios reciben advertencias de SmartScreen durante un tiempo, hasta que aumenta la reputación de ese certificado. Publicas MyApp-v2.exe. Los usuarios no reciben advertencias porque el certificado ya tiene buena reputación. Con el tiempo, tu certificado caduca y llega el momento de publicar MyApp-v47.exe. Renuevas tu certificado y los usuarios vuelven a recibir advertencias hasta que el nuevo certificado acumula reputación.
- Firmas tu código con un certificado EV (Extended Validation). Los usuarios nunca reciben advertencias, porque los certificados EV obtienen reputación instantánea en SmartScreen.
En resumen: firma tu código, da preferencia a un certificado EV (o a Azure Artifact Signing) para obtener reputación instantánea, y cuenta con un breve período de acumulación de reputación si usas certificados OV.
Firma en Windows
Obtener un certificado de firma de código
Azure Artifact Signing
Desde abril de 2024, la forma más eficaz de firmar el código de tu producto es mediante Azure Artifact Signing (anteriormente conocido como Azure Trusted Signing).
- Cuesta 10 USD al mes (o 120 USD al año), un precio similar o inferior al de los certificados de firma de código de otros emisores.
- Es una solución completamente en la nube: no requiere que te envíen ningún hardware físico (HSM).
- La firma se puede automatizar (p. ej., en tu pipeline de CI).
- Los certificados de Artifact Signing obtienen de forma integrada reputación instantánea en SmartScreen y Defender.
Velopack incluye compatibilidad integrada con Artifact Signing en Windows, Linux y macOS. Consulta Firma mediante Azure Artifact Signing más abajo para saber cómo configurarlo.
Otros proveedores de certificados
Si prefieres comprar un certificado de firma de código a otro proveedor, Microsoft enumera los siguientes emisores de confianza en su documentación:
También existen revendedores que pueden ofrecer certificados de emisores autorizados a precios más bajos, pero con el riesgo añadido de que no recibirás soporte oficial para esos certificados y de que los procedimientos de verificación de identidad pueden ser más complicados.
Ten en cuenta que, desde el 1 de junio de 2023, ha habido un cambio de política por el que ya no es posible descargar tu certificado de firma de código. Debe almacenarse en un HSM en la nube autorizado o, de lo contrario, se te enviará un HSM USB. Muchas de estas soluciones requieren pasos manuales y no son compatibles con la automatización / CI. Revísalo con atención antes de comprar.
Firma mediante Azure Artifact Signing
Azure Artifact Signing (anteriormente Trusted Signing) es un servicio de firma administrado de Microsoft y una de las formas más rentables de firmar tu aplicación.
Para obtener información detallada sobre Azure Artifact Signing, consulta la documentación oficial.
Desde Velopack 1.3, vpk firma directamente con Azure Artifact Signing (sin signtool.exe), por lo que --azureTrustedSignFile funciona al empaquetar aplicaciones de Windows en Windows, Linux y macOS. Los instaladores MSI solo se pueden compilar (y, por tanto, firmar) en Windows. Las versiones anteriores de Velopack usan signtool.exe y la dlib de Artifact Signing, y solo admiten esta opción en Windows.
- Primero tendrás que crear una cuenta de Azure en: https://azure.microsoft.com/pricing/purchase-options/azure-account. Esta cuenta debe tener una suscripción activa.
- Registra el proveedor de recursos de Azure Artifact Signing. Puedes hacerlo en Azure Portal o con la CLI de Azure siguiendo estas instrucciones.
- Crea el recurso de Azure Artifact Signing siguiendo estas instrucciones. Anota el nombre y la región que selecciones, ya que más adelante usarás estos valores para
CodeSigningAccountNameyEndpoint, respectivamente, en el archivo JSON de configuración de firma. - Crea una solicitud de validación de identidad siguiendo estas instrucciones. Este paso debe realizarse en Azure Portal. La validación de identidad puede hacerse para una organización o para un desarrollador individual. Este proceso puede tardar un tiempo, ya que Microsoft verifica la información de identidad. Vuelve a estos pasos cuando se haya completado el proceso de validación de identidad.
- Crea un perfil de certificado siguiendo estas instrucciones. Se admiten varios modelos de confianza. El modelo de confianza pública (Public Trust) es el más común y es adecuado para la mayoría de las aplicaciones. Anota el nombre del perfil de certificado, ya que más adelante usarás este valor como
CertificateProfileNameen el archivo JSON de configuración de firma. - Configura la autenticación con Azure Artifact Signing.
vpkutiliza la clase común DefaultAzureCredential para autenticarse con Azure. Esta clase admite autenticación de diversas maneras, incluidas las variables de entorno, la identidad administrada y la CLI de Azure. Después de instalar la CLI de Azure, ejecutaaz login. Si lo ejecutas dentro de GitHub Actions o de Azure DevOps, hay compatibilidad integrada que se encarga de realizar la autenticación necesaria. La identidad con la que inicies sesión necesita el rol Artifact Signing Certificate Profile Signer (anteriormente Trusted Signing Certificate Profile Signer) en la cuenta o en el perfil de certificado. - Crea el archivo JSON de metadatos de firma. Este archivo tiene tres parámetros obligatorios. El archivo debe tener este aspecto:
Encontrarás cada uno de estos valores en los pasos anteriores, donde creaste el recurso de Azure Artifact Signing y el perfil de certificado. Aunque no es obligatorio, este archivo suele llamarse{"Endpoint": "<Artifact Signing account endpoint>","CodeSigningAccountName": "<Artifact Signing account name>","CertificateProfileName": "<Certificate profile name>"}
metadata.json. Es el mismo formato de archivo que usa la integración con signtool de Microsoft, y también se admiten las siguientes propiedades opcionales:ExcludeCredentials: una lista de tipos de credenciales que se omitirán al autenticarse (p. ej.,["ManagedIdentityCredential", "EnvironmentCredential"]).AccessToken: un token de acceso obtenido previamente que se usará en lugar deDefaultAzureCredential(p. ej., deaz account get-access-token --resource https://codesigning.azure.net).CorrelationId: un identificador que se adjunta a cada solicitud de firma.
- Pasa el archivo JSON de metadatos al llamar a
vpk packusando--azureTrustedSignFile <path to json file>.vpkfirmará los binarios de tu aplicación,Setup.exey el MSI (si vas a compilar uno), y añadirá una marca de tiempo a cada firma usandohttp://timestamp.acs.microsoft.com. Los archivos que ya están firmados (por ejemplo, dependencias de terceros firmadas) se dejan tal cual.
Firma mediante signtool.exe
Normalmente, la firma se realiza con signtool.exe. Si ya usas esta herramienta para firmar tu aplicación, puedes pasar tus parámetros de firma directamente a Velopack (sin el comando 'sign').
Por ejemplo, si antes tu comando de firma era:
signtool.exe sign /td sha256 /fd sha256 /f yourCert.pfx /tr http://timestamp.comodoca.com
Ahora, con --signParams, sería:
vpk pack ... --signParams "/td sha256 /fd sha256 /f yourCert.pfx /tr http://timestamp.comodoca.com"
Usa siempre rutas absolutas en tus argumentos de firma, ya que no hay garantía de que signtool se ejecute en el mismo directorio de trabajo que vpk.
Si es la primera vez que usas signtool.exe, puedes consultar la referencia de la línea de comandos aquí. Te recomiendo que primero consigas que la firma funcione en un solo binario con signtool.exe antes de intentar que funcione con la CLI de Velopack.
Si usas un USB / HSM y obtienes el error de firma Error: SignerSign() failed." (-2147023673/0x800704c7), significa que te falta una contraseña / token de desbloqueo. Puedes añadirlo a tu comando de firma con los parámetros /csp /k. [Más información]
Ten cuidado al proporcionar parámetros con espacios. Debes envolver entre comillas todo lo que contenga espacios y escaparlas con una barra invertida. Por ejemplo, --signParams "/n \"My Cert Name\"". Si usas una tarea <Exec> de MSBuild o similar, tendrás que usar " en su lugar.
De forma predeterminada, Velopack firma 10 archivos por cada llamada a signtool.exe, para acelerar la firma y reducir el número de veces que tienes que interactuar con la consola si usas algún tipo de método de firma interactivo. Puedes desactivarlo con el argumento --signParallel 1.
Comandos y herramientas de firma personalizados
Si tienes requisitos de firma más avanzados, como una herramienta de firma personalizada (p. ej., AzureSignTool.exe), puedes proporcionar en su lugar una plantilla de comando, donde {{file}} es el binario que Velopack sustituirá y firmará:
vpk pack ... --signTemplate "AzureSignTool.exe sign ... {{file}}"
Lo anterior firmará un archivo cada vez, pero si tu herramienta de firma admite firmar varios archivos por lotes, puedes especificar {{file...}} en su lugar.
Firma multiplataforma
Desde Velopack 1.3, Azure Artifact Signing mediante --azureTrustedSignFile es compatible con Linux y macOS sin necesidad de herramientas adicionales. Si usas otro proveedor de certificados, o una versión anterior de Velopack, puedes usar una herramienta de terceros con --signTemplate.
JSign es una herramienta de firma de código versátil que se ejecuta en Linux, macOS y Windows. Admite una amplia gama de algoritmos de firma y servicios de marca de tiempo.
Para usarla con Velopack y Azure Artifact Signing, haz lo siguiente:
- Sigue los pasos anteriores para configurar Azure Artifact Signing
- Descarga la última versión de JSign desde https://ebourg.github.io/jsign/#files
- Instala la CLI de Azure e inicia sesión con
az login - Obtén un token de acceso ejecutando
az account get-access-token --resource https://codesigning.azure.net - Usa la opción
--signTemplatepara firmar tus archivos.
vpk pack ... --signTemplate "jsign --storetype TRUSTEDSIGNING --keystore <region> --storepass <api-access-token> --alias <account>/<profile> {{file}}"
Firma y notarización en OSX
La firma de código y la notarización son obligatorias para que los usuarios puedan ejecutar tu aplicación, por lo que es un paso imprescindible antes de desplegarla.
Crear certificados de firma de código
- Primero, tendrás que crear una cuenta en https://developer.apple.com, pagar la cuota anual de desarrollador y aceptar los acuerdos de licencia que correspondan.
- Ve a tus certificados: https://developer.apple.com/account/resources/certificates
- Haz clic en el icono (+) para crear nuevos certificados. Tienes que crear tanto un certificado
Developer ID Installercomo un certificadoDeveloper ID Applicationpara distribuir aplicaciones de Velopack fuera de la Mac App Store.
- Abre ambos certificados haciendo clic en ellos, pulsa Descargar y luego haz doble clic en el archivo ".cer" para instalarlo en tu llavero local.
Si tus certificados aparecen como no fiables en Acceso a Llaveros, o recibes una advertencia como "Warning: unable to build chain to self-signed root for signer "Developer ID Application: YourName", probablemente te falta en tu máquina un certificado de desarrollo que puedes descargar desde aquí: https://www.apple.com/certificateauthority/
Configurar un perfil de NotaryTool
- Crea una contraseña específica de app: https://support.apple.com/en-us/102654. Esta contraseña solo se te mostrará una vez, así que guárdala o anótala en algún lugar.
- Busca tu ID de equipo de Apple: https://developer.apple.com/account#MembershipDetailsCard
- Guarda las credenciales de tu cuenta de Apple en un nuevo perfil de NotaryTool:
xcrun notarytool store-credentials \--apple-id "yourapple@account.com" \--team-id "your-located-team-id" \--password "your-generated-app-specific-password" \"your-local-profile-name-here"
Ponerlo todo junto
Ahora que tienes instalados tu perfil de NotaryTool y los certificados de firma de código, puedes añadir los siguientes parámetros a tu comando pack:
vpk pack \
... \
--signAppIdentity "Developer ID Application: Your Name" \
--signInstallIdentity "Developer ID Installer: Your Name" \
--notaryProfile "your-local-profile-name-here"
Cuando se especifican estos parámetros y son válidos, Velopack firmará y notarizará automáticamente tu aplicación y los paquetes de instalación.
Velopack usará codesign y xcrun notarytool para firmar y notarizar tu aplicación. De forma predeterminada, estas herramientas usan el llavero predeterminado de tu dispositivo para encontrar los certificados y el perfil de notarización.
Si quieres usar otro llavero, debes instalar tus certificados y crear tu perfil de notarización en ese llavero, y usar el argumento --keychain {path} de Velopack
para indicar que Velopack debe buscar los certificados en un llavero que no es el predeterminado.
Si no proporcionas un archivo de entitlements (permisos) para el runtime reforzado, se te proporcionará automáticamente uno adecuado para la mayoría de las aplicaciones dotnet. Si tu aplicación requiere
permisos especiales y los predeterminados no son adecuados, debes proporcionar tus propios permisos de firma con --signEntitlements {path}. Ten en cuenta que el permiso App
Sandbox de macOS (com.apple.security.app-sandbox) no es compatible con Velopack; consulta la nota sobre las limitaciones de macOS para más detalles.
De forma predeterminada, Velopack realiza una firma "profunda" de todos los binarios de tu paquete. Si prefieres firmar previamente tus propios binarios y que Velopack los omita,
puedes pasar --signDisableDeep.
Aunque tu certificado aparezca como Developer ID Application: Your Name (TeamName) en Acceso a Llaveros, no debes incluir el nombre del equipo en
tus argumentos --signAppIdentity o --signInstallIdentity. Tu certificado debe ser simplemente Developer ID Application: Your Name, sin el equipo.
Automatizar la firma en CI/CD (Github Actions)
También es posible guardar tus certificados y credenciales de notarización como secretos de Actions y firmar tu código durante las compilaciones de CI.
- Github Actions
- Azure DevOps
-
Abre Acceso a Llaveros y ve al panel "Mis certificados".
-
Selecciona cada certificado (uno cada vez), haz clic derecho y selecciona "Exportar". Guárdalo como archivo p12 y anota la contraseña. Puedes usar la misma contraseña para ambos certificados.
consejoSi no ves la opción de exportar, o la exportación como
.p12está deshabilitada, es posible que tengas que cambiar el llavero o la pestaña que estás viendo. Debes estar en la pestaña "Mis certificados". Consulta https://stackoverflow.com/questions/15662377/unable-to-export-apple-production-push-ssl-certificate-in-p12-format para más información. -
Copia el contenido del certificado al portapapeles en base64, por ejemplo:
base64 -i CERT.p12 | pbcopy -
Crea 7 secretos de Github para tus flujos de trabajo de Actions
BUILD_CERTIFICATE_BASE64(b64 de tu certificado de aplicación)INSTALLER_CERTIFICATE_BASE64(b64 de tu certificado de instalador)P12_PASSWORD(contraseña de los certificados)APPLE_ID(tu nombre de usuario de Apple)APPLE_PASSWORD(tu contraseña específica de app del paso de notarización anterior)APPLE_TEAM(tu ID de equipo del paso de notarización anterior)KEYCHAIN_PASSWORD(puede ser cualquier cadena aleatoria; se usará para crear un nuevo llavero)
-
Añade a tu flujo de trabajo un paso que instale los certificados y el perfil del llavero. Este es un ejemplo:
name: App build & signon: pushjobs:build_with_signing:runs-on: macos-lateststeps:- name: Checkout repositoryuses: actions/checkout@v4- name: Install Apple certificates and notary profileenv:BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}INSTALLER_CERTIFICATE_BASE64: ${{ secrets.INSTALLER_CERTIFICATE_BASE64 }}P12_PASSWORD: ${{ secrets.P12_PASSWORD }}APPLE_ID: ${{ secrets.APPLE_ID }}APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}APPLE_TEAM: ${{ secrets.APPLE_TEAM }}KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}run: |# create variables for file pathsCERT_BUILD_PATH=$RUNNER_TEMP/build_certificate.p12CERT_INSTALLER_PATH=$RUNNER_TEMP/installer_certificate.p12KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db# import certificates from secretsecho -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERT_BUILD_PATHecho -n "$INSTALLER_CERTIFICATE_BASE64" | base64 --decode -o $CERT_INSTALLER_PATH# create temporary keychainsecurity create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATHsecurity set-keychain-settings -lut 21600 $KEYCHAIN_PATHsecurity unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH# import certificates to keychainsecurity import $CERT_BUILD_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATHsecurity import $CERT_INSTALLER_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATHsecurity list-keychain -d user -s $KEYCHAIN_PATH# create notarytool profilexcrun notarytool store-credentials --apple-id "$APPLE_ID" --team-id "$APPLE_TEAM" --password "$APPLE_PASSWORD" velopack-profile- name: Compile your app...- name: Create Velopack Releaserun: |dotnet tool install -g vpkvpk pack ... \--signAppIdentity "Developer ID Application: Your Name" \--signInstallIdentity "Developer ID Installer: Your Name" \--notaryProfile "velopack-profile" \--keychain $RUNNER_TEMP/app-signing.keychain-db# Or use dnx instead of installing globally:# - name: Create Velopack Release# run: |# dnx vpk --version 1.0.0 pack ... \# --signAppIdentity "Developer ID Application: Your Name" \# --signInstallIdentity "Developer ID Installer: Your Name" \# --notaryProfile "velopack-profile" \# --keychain $RUNNER_TEMP/app-signing.keychain-db# Replace 1.0.0 with your Velopack package version# Learn more: https://learn.microsoft.com/dotnet/core/tools/dotnet-tool-exec?WT.mc_id=DT-MVP-5003472- name: Clean up keychainif: ${{ always() }}run: security delete-keychain $RUNNER_TEMP/app-signing.keychain-db
La documentación de Azure DevOps de esta sección la aporta la comunidad y no ha sido verificada por el equipo de Velopack.
-
Abre Acceso a Llaveros y ve al panel "Mis certificados".
-
Selecciona cada certificado (uno cada vez), haz clic derecho y selecciona "Exportar". Guárdalo como archivo p12 y anota la contraseña. Puedes usar la misma contraseña para ambos certificados.
consejoSi no ves la opción de exportar, o la exportación como
.p12está deshabilitada, es posible que tengas que cambiar el llavero o la pestaña que estás viendo. Debes estar en la pestaña "Mis certificados". Consulta https://stackoverflow.com/questions/15662377/unable-to-export-apple-production-push-ssl-certificate-in-p12-format para más información. -
Copia el contenido del certificado al portapapeles en base64, por ejemplo:
base64 -i CERT.p12 | pbcopy -
Crea 7 secretos en Azure Key Vault y exponlos a Azure DevOps en el grupo de variables "Apple signing". Ten en cuenta que usamos Key Vault en lugar de los secretos de DevOps porque nuestros certificados son demasiado grandes (más de 4K) para guardarlos en secretos de DevOps.
P12-PASSWORD(contraseña de los certificados)APPLE-ID(tu nombre de usuario de Apple)APPLE-PASSWORD(tu contraseña específica de app del paso de notarización anterior)APPLE-TEAM(tu ID de equipo del paso de notarización anterior)KEYCHAIN-PASSWORD(puede ser cualquier cadena aleatoria; se usará para crear un nuevo llavero)BUILD-CERTIFICATE-BASE64(base64 de tu certificado de aplicación)INSTALLER-CERTIFICATE-BASE64(base64 de tu certificado de instalador)
-
Añade pasos a tu pipeline para cargar los secretos, firmar y limpiar:
El YAML de configuración:
variables:- group: Apple signingsteps:- bash: |# create variables for file pathsCERT_BUILD_PATH=$AGENT_TEMPDIRECTORY/build_certificate.p12CERT_INSTALLER_PATH=$AGENT_TEMPDIRECTORY/installer_certificate.p12KEYCHAIN_PATH=$AGENT_TEMPDIRECTORY/app-signing.keychain-db# import certificates from secretsecho -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o $CERT_BUILD_PATHecho -n "$INSTALLER_CERTIFICATE_BASE64" | base64 --decode -o $CERT_INSTALLER_PATH# create temporary keychainsecurity create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATHsecurity set-keychain-settings -lut 21600 $KEYCHAIN_PATHsecurity unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH# import certificates to keychainsecurity import $CERT_BUILD_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATHsecurity import $CERT_INSTALLER_PATH -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATHsecurity list-keychain -d user -s $KEYCHAIN_PATH# create notarytool profilexcrun notarytool store-credentials --apple-id "$APPLE_ID" --team-id "$APPLE_TEAM" --password "$APPLE_PASSWORD" --keychain $KEYCHAIN_PATH velopack-profileenv:BUILD_CERTIFICATE_BASE64: $(BUILD-CERTIFICATE-BASE64)INSTALLER_CERTIFICATE_BASE64: $(INSTALLER-CERTIFICATE-BASE64)P12_PASSWORD: $(P12-PASSWORD)APPLE_ID: $(APPLE-ID)APPLE_PASSWORD: $(APPLE-PASSWORD)APPLE_TEAM: $(APPLE-TEAM)KEYCHAIN_PASSWORD: $(KEYCHAIN-PASSWORD)displayName: 🛠️ Install Apple certs and notary profilePara limpiar:
- bash: security delete-keychain $AGENT_TEMPDIRECTORY/app-signing.keychain-dbdisplayName: 🧹 Clean up keychaincondition: always()Firmar en Mac (asumiendo un script de PowerShell):
# Add signing parametersif ($IsMacOS) {$vpkCommand += @('--signAppIdentity','Developer ID Application: Your Name','--signInstallIdentity','Developer ID Installer: Your Name','--notaryProfile','velopack-profile','--keychain','$(Agent.TempDirectory)/app-signing.keychain-db')}