Skip to Content
Nuova versione 12 disponibile 🎉
ObfuscatorConformità FIPS

Conformità FIPS

Gli assembly protetti con Babel Obfuscator funzionano sugli host con FIPS abilitato. Questa pagina spiega come si comportano su questi host le funzionalità di protezione che si basano sulla decifratura in fase di esecuzione, cioè cifratura del codice (MSIL), cifratura delle stringhe, cifratura delle risorse e cifratura di valori e array. Descrive inoltre un problema di avvio che puoi incontrare nei container e come risolverlo: al momento dell’offuscamento, proteggendo l’assembly con l’AES gestito e autonomo di Babel, oppure a livello di ambiente.

Contesto

Molti clienti distribuiscono su host il cui sistema operativo funziona in modalità FIPS: su Linux questa condizione è esposta come /proc/sys/crypto/fips_enabled = 1. In questa modalità il provider crittografico della piattaforma (OpenSSL su Linux) deve eseguire ogni operazione crittografica tramite un modulo FIPS certificato.

Un problema frequente si presenta quando un container eredita il flag FIPS dell’host ma la sua immagine di base non include un provider FIPS di OpenSSL certificato. OpenSSL 3 tenta allora di entrare in modalità FIPS, non riesce a caricare il modulo del provider FIPS e finisce in uno stato non funzionante in cui falliscono tutte le operazioni di digest e di cifratura, non solo quelle che FIPS normalmente vieterebbe.

Si tratta di una condizione dell’ambiente, non di un difetto dell’assembly offuscato o di Babel Obfuscator. È documentata indipendentemente da Babel: vedi dotnet/dotnet-docker#5849  e dotnet/runtime#87884 . Riguarda qualsiasi operazione crittografica .NET basata su OpenSSL nel processo, TLS compreso (HttpClient, gRPC), non solo il codice offuscato.

Come può manifestarsi negli assembly offuscati

Quando un assembly è protetto con una funzionalità che decifra il contenuto in fase di esecuzione, in particolare la cifratura del codice e la cifratura delle stringhe, Babel inietta un piccolo runtime che usa il provider crittografico della piattaforma per decifrare i corpi dei metodi e le stringhe. Su un host con FIPS non funzionante quel provider è inutilizzabile e, poiché la decifratura viene eseguita all’interno di un inizializzatore di tipo, l’assembly non riesce ad avviarsi prima che venga eseguito qualsiasi tuo codice:

System.TypeInitializationException: The type initializer for '...' threw an exception. ---> Interop+Crypto+OpenSslCryptographicException: error:0308010C:digital envelope routines::unsupported at System.Security.Cryptography.AesImplementation.CreateTransform(...)

Puoi prevenire questo errore di avvio al momento dell’offuscamento, proteggendo l’assembly con l’algoritmo AES gestito di Babel: il runtime iniettato decifra allora senza il provider crittografico della piattaforma. Vedi più avanti Avviare l’assembly su un host con FIPS non funzionante grazie all’AES gestito. Correggere l’ambiente OpenSSL (descritto anch’esso più avanti) resta comunque consigliato quando hai il controllo del container, perché risolve anche le altre operazioni del processo basate su OpenSSL, come TLS.

Avviare l’assembly su un host con FIPS non funzionante grazie all’AES gestito

Babel Obfuscator può includere nell’assembly protetto un decifratore AES gestito e autonomo, così il runtime iniettato non dipende più dal provider crittografico della piattaforma. Proteggi l’assembly con il valore encryption=aesmanaged dell’opzione --use:

babel MyApp.dll --msilencryption --use encryption=aesmanaged

oppure, in un progetto MSBuild / .babel:

<Use>encryption=aesmanaged</Use>

L’offuscatore continua a cifrare con il provider della piattaforma sull’host di build (che funziona correttamente) e produce lo stesso testo cifrato; cambia soltanto il decifratore incluso nell’assembly protetto. In questo modo l’assembly si avvia su un host con FIPS non funzionante senza alcuna modifica all’ambiente. Gli assembly protetti con una versione precedente di Babel devono essere offuscati di nuovo per includere il decifratore gestito.

Prestazioni. Il decifratore gestito lavora a circa 40 MB/s, contro i diversi GB/s dell’AES della piattaforma con accelerazione hardware. Per la cifratura delle stringhe, delle risorse e per quella più comune del codice (con cache) è un costo sostenuto una sola volta all’avvio e non si nota. Fa eccezione la cifratura del codice su un metodo contrassegnato con cache=false, il cui corpo viene decifrato a ogni chiamata: evita di combinare cache=false con encryption=aesmanaged sui metodi dei percorsi eseguiti più di frequente e mantieni abilitata la cache dei metodi (l’impostazione predefinita), così la decifratura avviene una volta sola.

Risolvere il problema nei container

Rendi OpenSSL utilizzabile all’interno del container. Entrambe le opzioni risolvono il sintomo del runtime di offuscamento e ogni altra operazione del tuo processo basata su OpenSSL (per esempio se lo stesso assembly usa anche Babel Licensing o TLS).

Opzione 1: non entrare automaticamente in modalità FIPS nel container

Nelle immagini .NET basate su Ubuntu, OpenSSL rispetta la variabile d’ambiente OPENSSL_FORCE_FIPS_MODE. Impostala a 0, così OpenSSL non tenta di entrare in modalità FIPS con un provider che l’immagine non include.

In un Dockerfile:

ENV OPENSSL_FORCE_FIPS_MODE=0

oppure in docker-compose.yml:

environment: OPENSSL_FORCE_FIPS_MODE: 0

Usa questa opzione quando il container in sé non deve essere validato FIPS: l’host resta con FIPS abilitato e solo l’OpenSSL di questo container rinuncia all’attivazione automatica di FIPS, che non funziona.

Opzione 2: usa un’immagine di base con un provider FIPS certificato

Se la conformità FIPS è richiesta all’interno del container, usa un’immagine di base che include un provider FIPS validato, così lo strato crittografico si inizializza correttamente anziché fallire:

  • Immagini .NET Azure Linux 3.0 (mcr.microsoft.com/dotnet/aspnet:8.0-azurelinux3.0 e simili), che includono il provider SymCrypt di Microsoft, certificato FIPS,
  • immagini .NET basate su Red Hat UBI 9 (registry.access.redhat.com/ubi9/dotnet-90 e simili), oppure
  • Ubuntu Pro con i pacchetti OpenSSL certificati FIPS.

Verificare l’ambiente

Un controllo rapido dall’interno del container ti dice se OpenSSL funziona correttamente:

# Fails on a broken-FIPS host, succeeds once fixed echo test | openssl dgst -sha1
  • Errore error:03000086 (o un messaggio che segnala che fips.so non può essere caricato): OpenSSL è nello stato non funzionante; applica l’opzione 1 o 2.
  • Una normale riga SHA1(stdin)= ...: OpenSSL funziona correttamente e gli assembly offuscati si avviano normalmente.

Se non puoi modificare l’ambiente

Se non hai il controllo dell’immagine di base o delle variabili d’ambiente e il target deve restare rigorosamente vincolato a FIPS, proteggi l’assembly con l’algoritmo AES gestito descritto sopra (--use encryption=aesmanaged), così il decifratore iniettato non ha bisogno del provider della piattaforma. In questo modo un assembly protetto si avvia anche su un host con OpenSSL non funzionante senza toccare l’ambiente, e restano disponibili tutte le funzionalità di decifratura in fase di esecuzione: cifratura del codice, cifratura delle stringhe, cifratura delle risorse e cifratura di valori e array. Tieni presente che le altre operazioni dello stesso processo basate su OpenSSL (come TLS) continueranno a fallire finché l’ambiente non viene corretto. Contatta l’assistenza  se ti servono indicazioni per una distribuzione specifica.

Last updated on