Dit artikel is een technisch voorstel (Issue #81639) om de manier waarop FIPS140-cryptografische code wordt opgenomen in Go-binaries te optimaliseren. De auteur stelt vast dat een aanzienlijke hoeveelheid FIPS-gerelateerde code standaard wordt meegecompileerd, zelfs wanneer deze niet actief wordt gebruikt. Dit resulteert in onnodig grote binaries, verspilling van geheugen en het vervuilen van caches.
Door middel van testprogramma's en het gebruik van objdump wordt aangetoond dat zelfs een eenvoudige import van crypto/rand een enorme hoeveelheid extra implementaties meeslept, waaronder diverse AES-, SHA- en HMAC-routines.
De voorgestelde oplossing omvat:
- De introductie van een nieuwe standaardwaarde:
GOFIPS140=disabled.
- Het wijzigen van
fips140.Enabled van een variabele naar een constante (const), waardoor de compiler ongebruikte codepaden effectief kan verwijderen.
Het doel is om de standaard Go-binaries weer slanker te maken, terwijl de FIPS-functionaliteit beschikbaar blijft voor de specifieke groep gebruikers die dit vereist.
Voorstel: voorkom onnodige opblozing van crypto-code in crypto/fips140
Samenvatting
De FIPS140-code, en met name de Random Number Generator (RNG), bevindt zich ongebruikt en volumineus in de overgrote meerderheid van de Go-binaries. Slechts een zeer specifieke groep gebruikers doorloopt de stappen om deze technisch gezien grotendeels nutteloze code in te schakelen. Hierdoor blijft de code aanwezig, wat resulteert in verspilling van geheugen (de init-functies worden nog steeds aangeroepen), schijfruimte en het vervuilen van caches. Het is een ongewenst gewicht voor een voorheen strakke set cryptobibliotheken.
Dit voorstel pleit voor de toevoeging van een nieuwe standaardwaarde, GOFIPS140=disabled, om te voorkomen dat ongebruikte FIPS-code wordt meegecompileerd.
Motivatie
De nieuwe fips140-code introduceert veel indirectie en vergroot de omvang van de resulterende binaries aanzienlijk, zelfs wanneer de functies uitgeschakeld zijn of niet worden gebruikt. Het gebruik ervan wordt beheerd door een GODEBUG-vlag die standaard op 'uit' staat, maar de code wordt desalniettemin altijd in Go-binaries gecompileerd.
Naast het routeren van grote hoeveelheden cryptografie via dit framework (om vervolgens vroegtijdig af te breken wanneer het niet is ingeschakeld via de GODEBUG-vlag), importeert het ook grote hoeveelheden extra cryptografie en complexiteit.
Voor zover ik kan vaststellen, voegt het naast de indirectie via het framework ook vertakkende codepaden toe aan:
- TLS
- RSA/PKCS1
- De wrapper-functies voor de Random Number Generator (RNG)
- AES/GCM
Het toevoegen van deze ongebruikte code is in al deze gevallen onwenselijk. Deze zouden in plaats daarvan moeten worden afgeschermd met een compile-time constante (waarbij het Enabled-symbool zou kunnen veranderen van var naar const). De situatie rondom de RNG is echter het meest schrijnend, dus daarop focus ik hier om mijn punt te illustreren.
Testprogramma's
Ik heb twee testprogramma's gemaakt:
tester1:
package main
func main() {
println("hello")
}
tester2:
package main
import "crypto/rand"
func main() {
var b [1]byte
rand.Read(b[:])
println("hello", b[0])
}
Wanneer we kijken naar welke cryptopakketten tester2 toevoegt, zouden we verwachten dat dit crypto/rand is, plus enkele interne crypto-elementen voor het verzenden naar systeemoproepen (syscalls) om kwalitatieve willekeurige bytes te verkrijgen. Dat is echter niet wat er gebeurt:
$ comm -13 <(go tool objdump tester1 | grep ^TEXT\ crypto | sort) <(go tool objdump tester2 | grep ^TEXT\ crypto | sort)
TEXT crypto/fips140.init(SB) <autogenerated>
TEXT crypto.init(SB) <autogenerated>
TEXT crypto/internal/entropy/v1%2e0%2e0.digestBytes(SB) /usr/lib/go/src/crypto/internal/entropy/v1.0.0/sha384.go
TEXT crypto/internal/entropy/v1%2e0%2e0.newSource(SB) /usr/lib/go/src/crypto/internal/entropy/v1.0.0/entropy.go
TEXT crypto/internal/entropy/v1%2e0%2e0.Samples(SB) /usr/lib/go/src/crypto/internal/entropy/v1.0.0/entropy.go
TEXT crypto/internal/entropy/v1%2e0%2e0.Seed(SB) /usr/lib/go/src/crypto/internal/entropy/v1.0.0/entropy.go
TEXT crypto/internal/entropy/v1%2e0%2e0.sha384Block(SB) /usr/lib/go/src/crypto/internal/entropy/v1.0.0/sha384.go
TEXT crypto/internal/entropy/v1%2e0%2e0.SHA384(SB) /usr/lib/go/src/crypto/internal/entropy/v1.0.0/sha384.go
TEXT crypto/internal/entropy/v1%2e0%2e0.(*source).Sample(SB) /usr/lib/go/src/crypto/internal/entropy/v1.0.0/entropy.go
TEXT crypto/internal/fips140/aes.(*Block).BlockSize(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes.go
TEXT crypto/internal/fips140/aes.(*CBCDecrypter).CryptBlocks(SB) /usr/lib/go/src/crypto/internal/fips140/aes/cbc.go
TEXT crypto/internal/fips140/aes.(*CBCEncrypter).CryptBlocks(SB) /usr/lib/go/src/crypto/internal/fips140/aes/cbc.go
TEXT crypto/internal/fips140/aes.cryptBlocksDecGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/aes/cbc.go
TEXT crypto/internal/fips140/aes.cryptBlocksEncGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/aes/cbc.go
TEXT crypto/internal/fips140/aes.ctrBlocks1Asm.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr_amd64.s
TEXT crypto/internal/fips140/aes.ctrBlocks1(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr_asm.go
TEXT crypto/internal/fips140/aes.ctrBlocks2Asm.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr_amd64.s
TEXT crypto/internal/fips140/aes.ctrBlocks2(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr_asm.go
TEXT crypto/internal/fips140/aes.ctrBlocks4Asm.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr_amd64.s
TEXT crypto/internal/fips140/aes.ctrBlocks4(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr_asm.go
TEXT crypto/internal/fips140/aes.ctrBlocks8Asm.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr_amd64.s
TEXT crypto/internal/fips140/aes.ctrBlocks8(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr_asm.go
TEXT crypto/internal/fips140/aes.ctrBlocks(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr.go
TEXT crypto/internal/fips140/aes.(*CTR).XORKeyStreamAt(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr.go
TEXT crypto/internal/fips140/aes.(*CTR).XORKeyStream(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr.go
TEXT crypto/internal/fips140/aes.decryptBlockAsm.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_amd64.s
TEXT crypto/internal/fips140/aes.decryptBlockGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_generic.go
TEXT crypto/internal/fips140/aes.decryptBlock(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_asm.go
TEXT crypto/internal/fips140/aes.encryptBlockAsm.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_amd64.s
TEXT crypto/internal/fips140/aes.encryptBlockGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_generic.go
TEXT crypto/internal/fips140/aes.encryptBlock(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_asm.go
TEXT crypto/internal/fips140/aes.expandKeyAsm.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_amd64.s
TEXT crypto/internal/fips140/aes.expandKeyGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_generic.go
TEXT crypto/internal/fips140/aes/gcm.(*CMAC).deriveSubkeys(SB) /usr/lib/go/src/crypto/internal/fips140/aes/gcm/cmac.go
TEXT crypto/internal/fips140/aes/gcm.(*CMAC).MAC(SB) /usr/lib/go/src/crypto/internal/fips140/aes/gcm/cmac.go
TEXT crypto/internal/fips140/aes/gcm.(*CounterKDF).DeriveKey(SB) /usr/lib/go/src/crypto/internal/fips140/aes/gcm/ctrkdf.go
TEXT crypto/internal/fips140/aes/gcm.init.0.func1(SB) /usr/lib/go/src/crypto/internal/fips140/aes/gcm/cast.go
TEXT crypto/internal/fips140/aes/gcm.init.0(SB) /usr/lib/go/src/crypto/internal/fips140/aes/gcm/cast.go
TEXT crypto/internal/fips140/aes/gcm.init.1(SB) /usr/lib/go/src/crypto/internal/fips140/aes/gcm/gcm_asm.go
TEXT crypto/internal/fips140/aes/gcm.init(SB) <autogenerated>
TEXT crypto/internal/fips140/aes.init.0(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_asm.go
TEXT crypto/internal/fips140/aes.init.1.func1(SB) /usr/lib/go/src/crypto/internal/fips140/aes/cast.go
TEXT crypto/internal/fips140/aes.init.1(SB) /usr/lib/go/src/crypto/internal/fips140/aes/cast.go
TEXT crypto/internal/fips140/aes.init(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_asm.go
TEXT crypto/internal/fips140/aes.(*KeySizeError).Error(SB) <autogenerated>
TEXT crypto/internal/fips140/aes.KeySizeError.Error(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes.go
TEXT crypto/internal/fips140/aes.newBlock(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_asm.go
TEXT crypto/internal/fips140/aes.newOutlined(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes.go
TEXT crypto/internal/fips140.CAST(SB) /usr/lib/go/src/crypto/internal/fips140/cast.go
TEXT crypto/internal/fips140/check.init.0(SB) /usr/lib/go/src/crypto/internal/fips140/check/check.go
TEXT crypto/internal/fips140deps/cpu.init(SB) /usr/lib/go/src/crypto/internal/fips140deps/cpu/cpu.go
TEXT crypto/internal/fips140deps/time.monoTime(SB) /usr/lib/go/src/runtime/time.go
TEXT crypto/internal/fips140/drbg.(*Counter).Generate(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/ctrdrbg.go
TEXT crypto/internal/fips140/drbg.(*Counter).Reseed(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/ctrdrbg.go
TEXT crypto/internal/fips140/drbg.(*Counter).update(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/ctrdrbg.go
TEXT crypto/internal/fips140/drbg.getEntropy(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/entropy_fips140.go
TEXT crypto/internal/fips140/drbg.init.0.func1(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/cast.go
TEXT crypto/internal/fips140/drbg.init.0(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/cast.go
TEXT crypto/internal/fips140/drbg.init.func1(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/rand.go
TEXT crypto/internal/fips140/drbg.init(SB) <autogenerated>
TEXT crypto/internal/fips140/drbg.NewCounter(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/ctrdrbg.go
TEXT crypto/internal/fips140/drbg.Read.func1(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/rand.go
TEXT crypto/internal/fips140/drbg.Read(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/rand.go
TEXT crypto/internal/fips140.fatal(SB) /usr/lib/go/src/runtime/panic.go
TEXT crypto/internal/fips140.getIndicator(SB) /usr/lib/go/src/runtime/runtime1.go
TEXT crypto/internal/fips140/hmac.(*HMAC).BlockSize(SB) /usr/lib/go/src/crypto/internal/fips140/hmac/hmac.go
TEXT crypto/internal/fips140/hmac.(*HMAC).Reset(SB) /usr/lib/go/src/crypto/internal/fips140/hmac/hmac.go
TEXT crypto/internal/fips140/hmac.(*HMAC).Sum(SB) /usr/lib/go/src/crypto/internal/fips140/hmac/hmac.go
TEXT crypto/internal/fips140/hmac.(*HMAC).Write(SB) /usr/lib/go/src/crypto/internal/fips140/hmac/hmac.go
TEXT crypto/internal/fips140/hmac.init.0.func1(SB) /usr/lib/go/src/crypto/internal/fips140/hmac/cast.go
TEXT crypto/internal/fips140/hmac.init.0(SB) /usr/lib/go/src/crypto/internal/fips140/hmac/cast.go
TEXT crypto/internal/fips140/hmac.New[go.shape.*uint8].func1.1(SB) /usr/lib/go/src/crypto/internal/fips140/hmac/hmac.go
TEXT crypto/internal/fips140/hmac.New[go.shape.*uint8].func1(SB) /usr/lib/go/src/crypto/internal/fips140/hmac/hmac.go
TEXT crypto/internal/fips140/hmac.New[go.shape.*uint8](SB) /usr/lib/go/src/crypto/internal/fips140/hmac/hmac.go
TEXT crypto/internal/fips140.init.0(SB) /usr/lib/go/src/crypto/internal/fips140/fips140.go
TEXT crypto/internal/fips140.init(SB) <autogenerated>
TEXT crypto/internal/fips140.RecordApproved(SB) /usr/lib/go/src/crypto/internal/fips140/indicator.go
TEXT crypto/internal/fips140.setIndicator(SB) /usr/lib/go/src/runtime/runtime1.go
TEXT crypto/internal/fips140/sha256.blockAVX2.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256block_amd64.s
TEXT crypto/internal/fips140/sha256.blockGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256block.go
TEXT crypto/internal/fips140/sha256.block(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256block_amd64.go
TEXT crypto/internal/fips140/sha256.blockSHANI.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256block_amd64.s
TEXT crypto/internal/fips140/sha256.(*Digest).AppendBinary(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256.go
TEXT crypto/internal/fips140/sha256.(*Digest).BlockSize(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256.go
TEXT crypto/internal/fips140/sha256.(*Digest).checkSum(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256.go
TEXT crypto/internal/fips140/sha256.(*Digest).MarshalBinary(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256.go
TEXT crypto/internal/fips140/sha256.(*Digest).Reset(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256.go
TEXT crypto/internal/fips140/sha256.(*Digest).Sum(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256.go
TEXT crypto/internal/fips140/sha256.(*Digest).UnmarshalBinary(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256.go
TEXT crypto/internal/fips140/sha256.(*Digest).Write(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256.go
TEXT crypto/internal/fips140/sha256.init.0.func1(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/cast.go
TEXT crypto/internal/fips140/sha256.init.0(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/cast.go
TEXT crypto/internal/fips140/sha256.init.1(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256block_amd64.go
TEXT crypto/internal/fips140/sha256.init(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256block_amd64.go
TEXT crypto/internal/fips140/sha256.New(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256.go
TEXT crypto/internal/fips140/sha3.bytepadWrite(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/shake.go
TEXT crypto/internal/fips140/sha3.(*Digest).padAndPermute(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/sha3.go
TEXT crypto/internal/fips140/sha3.(*Digest).readGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/sha3.go
TEXT crypto/internal/fips140/sha3.(*Digest).sumGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/sha3.go
TEXT crypto/internal/fips140/sha3.(*Digest).Sum(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/sha3.go
TEXT crypto/internal/fips140/sha3.(*Digest).writeGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/sha3.go
TEXT crypto/internal/fips140/sha3.(*Digest).Write(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/sha3.go
TEXT crypto/internal/fips140/sha3.init.0.func1(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/cast.go
TEXT crypto/internal/fips140/sha3.init.0(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/cast.go
TEXT crypto/internal/fips140/sha3.keccakF1600.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/sha3_amd64.s
TEXT crypto/internal/fips140/sha3.newCShake128(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/shake.go
TEXT crypto/internal/fips140/sha3.newCShake(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/shake.go
TEXT crypto/internal/fips140/sha512.blockAVX2.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512block_amd64.s
TEXT crypto/internal/fips140/sha512.blockGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512block.go
TEXT crypto/internal/fips140/sha512.block(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512block_amd64.go
TEXT crypto/internal/fips140/sha512.(*Digest).checkSum(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512.go
TEXT crypto/internal/fips140/sha512.(*Digest).Reset(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512.go
TEXT crypto/internal/fips140/sha512.(*Digest).Sum(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512.go
TEXT crypto/internal/fips140/sha512.(*Digest).Write(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512.go
TEXT crypto/internal/fips140/sha512.init.0.func1(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512block_amd64.go
TEXT crypto/internal/fips140/sha512.init.0(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512block_amd64.go
TEXT crypto/internal/fips140/sha512.init.1(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512block_amd64.go
TEXT crypto/internal/fips140/sha512.init(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512block_amd64.go
TEXT crypto/internal/fips140/subtle.xorBytes.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/subtle/xor_amd64.s
TEXT crypto/internal/fips140/subtle.XORBytes(SB) /usr/lib/go/src/crypto/internal/fips140/subtle/xor.go
TEXT crypto/internal/impl.Register(SB) /usr/lib/go/src/crypto/internal/impl/impl.go
TEXT crypto/internal/rand.(*reader).Read(SB) <autogenerated>
TEXT crypto/internal/rand.reader.Read(SB) /usr/lib/go/src/crypto/internal/rand/rand.go
TEXT crypto/internal/sysrand.fatal(SB) /usr/lib/go/src/runtime/panic.go
TEXT crypto/internal/sysrand.Read.deferwrap1(SB) /usr/lib/go/src/crypto/internal/sysrand/rand.go
TEXT crypto/internal/sysrand.read(SB) /usr/lib/go/src/crypto/internal/sysrand/rand_getrandom.go
TEXT crypto/internal/sysrand.Read(SB) /usr/lib/go/src/crypto/internal/sysrand/rand.go
TEXT crypto/internal/sysrand.urandomRead.func1(SB) /usr/lib/go/src/crypto/internal/sysrand/rand.go
TEXT crypto/internal/sysrand.urandomRead(SB) /usr/lib/go/src/crypto/internal/sysrand/rand.go
TEXT crypto/internal/sysrand.warnBlocked(SB) /usr/lib/go/src/crypto/internal/sysrand/rand.go
TEXT crypto/rand.fatal(SB) /usr/lib/go/src/runtime/panic.go
TEXT crypto/rand.init(SB) <autogenerated>
TEXT crypto/rand.Read(SB) /usr/lib/go/src/crypto/rand/rand.go
Hieruit volgt dat de volgende elementen worden meegeleverd:
- Een bizarre 'voodoo magic' userspace entropy-collector.
- Een gespecialiseerde SHA384-implementatie voor deze entropy-collector.
- Een AES-implementatie.
- Een AES-NI versnelde AES-implementatie.
- Een CTR-implementatie voor AES.
- Een GCM-implementatie voor AES.
- Code voor CPU-detectie.
- Een implementatie van een FIPS-gespecificeerd DRBG-algoritme.
- Een HMAC-implementatie.
- Een SHA256-implementatie.
- Een AVX2-versnelde SHA256-implementatie.
- Een SHA3-implementatie (inclusief cSHAKE).
- Een AVX2-versnelde SHA3-implementatie.
- Een SHA512-implementatie.
- Diverse generieke XOR-bytes routines.
- De eigenlijke syscall-wrappers hiervoor (
crypto/internal/sysrand en crypto/rand).
Dit lijkt me overdreven. Hoewel ik begrijp dat sommige gebruikers gedwongen zijn FIPS-RNG te gebruiken, zou dit in een eigen hoek moeten worden geplaatst en niet standaard in elke Go-binary worden gecompileerd die crypto/rand gebruikt, zeker niet als het niet wordt gebruikt. Dit is een enorme hoeveelheid extra code.
Overwegingen
Zoals eerder vermeld, wordt dit alles beheerd door het lid fips140.Enabled, dat wordt aangestuurd door GODEBUG. Ik stel voor om fips140.Enabled te veranderen van een var naar een const, zodat de compiler de ongebruikte code kan verwijderen. Bepaalde complexe afhankelijkheidsketens kunnen vervolgens worden opgelost door de fips140 build-tag te gebruiken in specifieke bestanden. Dit betekent dat alle aanroepen nog steeds via FIPS140-trampolines verlopen, maar de eigenlijke algoritmen en overbodige code worden verwijderd. De trampolines kunnen bovendien grotendeels worden geïnlined.
Ik heb hierover informeel gesproken met @FiloSottile, die zorgen uitte over de impact op testen en CI. Een deel van dit voorstel omvat daarom het herzien van de tests, zodat onderdelen indien nodig opnieuw worden gecompileerd. De huidige CL-stack doet dit op een vrij nette manier.
Voorstel
Concreet stelt dit voorstel een nieuwe standaardwaarde voor: GOFIPS140=disabled. Dit houdt in dat binaries geen FIPS-specifieke paden (zoals de RNG en diverse extra vertakkingen) compileren.
De onderstaande tabel toont de wijzigingen in de GOFIPS140-variabele:
| Waarde | Voorheen | Na wijziging |
| Niet ingesteld | Standaard 'uit' | Standaard 'disabled' |
| disabled | Ongeldig | FIPS-modus niet beschikbaar; fips140.Enabled is const false |
| off | FIPS-ondersteuning inbegrepen, uitgeschakeld bij opstarten | Ongewijzigd |
| latest | Huidige module, standaard ingeschakeld | Ongewijzigd |
| certified | Gecertificeerde snapshot, standaard ingeschakeld | Ongewijzigd |
| inprocess | Snapshot in certificeringsproces, standaard ingeschakeld | Ongewijzigd |
| Versienummer | Gespecificeerde snapshot, standaard ingeschakeld | Ongewijzigd |
Implementatie
Er is een reeks CL's (Change Lists) beschikbaar op https://go-review.googlesource.com/c/go/+/836445 die dit implementeren en het testen automatiseren om de toekomstige onderhoudslast te verminderen.
Voorstel: voorkom onnodige opblozing van crypto-code in crypto/fips140
Samenvatting
De FIPS140-code, en met name de Random Number Generator (RNG), bevindt zich ongebruikt en volumineus in de overgrote meerderheid van de Go-binaries. Slechts een zeer specifieke groep gebruikers doorloopt de stappen om deze technisch gezien grotendeels nutteloze code in te schakelen. Hierdoor blijft de code aanwezig, wat resulteert in verspilling van geheugen (de init-functies worden nog steeds aangeroepen), schijfruimte en het vervuilen van caches. Het is een ongewenst gewicht voor een voorheen strakke set cryptobibliotheken.
Dit voorstel pleit voor de toevoeging van een nieuwe standaardwaarde, GOFIPS140=disabled, om te voorkomen dat ongebruikte FIPS-code wordt meegecompileerd.
Motivatie
De nieuwe fips140-code introduceert veel indirectie en vergroot de omvang van de resulterende binaries aanzienlijk, zelfs wanneer de functies uitgeschakeld zijn of niet worden gebruikt. Het gebruik ervan wordt beheerd door een GODEBUG-vlag die standaard op 'uit' staat, maar de code wordt desalniettemin altijd in Go-binaries gecompileerd.
Naast het routeren van grote hoeveelheden cryptografie via dit framework (om vervolgens vroegtijdig af te breken wanneer het niet is ingeschakeld via de GODEBUG-vlag), importeert het ook grote hoeveelheden extra cryptografie en complexiteit.
Voor zover ik kan vaststellen, voegt het naast de indirectie via het framework ook vertakkende codepaden toe aan:
- TLS
- RSA/PKCS1
- De wrapper-functies voor de Random Number Generator (RNG)
- AES/GCM
Het toevoegen van deze ongebruikte code is in al deze gevallen onwenselijk. Deze zouden in plaats daarvan moeten worden afgeschermd met een compile-time constante (waarbij het Enabled-symbool zou kunnen veranderen van var naar const). De situatie rondom de RNG is echter het meest schrijnend, dus daarop focus ik hier om mijn punt te illustreren.
Testprogramma's
Ik heb twee testprogramma's gemaakt:
tester1:
package main
func main() {
println("hello")
}
tester2:
package main
import "crypto/rand"
func main() {
var b [1]byte
rand.Read(b[:])
println("hello", b[0])
}
Wanneer we kijken naar welke cryptopakketten tester2 toevoegt, zouden we verwachten dat dit crypto/rand is, plus enkele interne crypto-elementen voor het verzenden naar systeemoproepen (syscalls) om kwalitatieve willekeurige bytes te verkrijgen. Dat is echter niet wat er gebeurt:
$ comm -13 <(go tool objdump tester1 | grep ^TEXT\ crypto | sort) <(go tool objdump tester2 | grep ^TEXT\ crypto | sort)
TEXT crypto/fips140.init(SB) <autogenerated>
TEXT crypto.init(SB) <autogenerated>
TEXT crypto/internal/entropy/v1%2e0%2e0.digestBytes(SB) /usr/lib/go/src/crypto/internal/entropy/v1.0.0/sha384.go
TEXT crypto/internal/entropy/v1%2e0%2e0.newSource(SB) /usr/lib/go/src/crypto/internal/entropy/v1.0.0/entropy.go
TEXT crypto/internal/entropy/v1%2e0%2e0.Samples(SB) /usr/lib/go/src/crypto/internal/entropy/v1.0.0/entropy.go
TEXT crypto/internal/entropy/v1%2e0%2e0.Seed(SB) /usr/lib/go/src/crypto/internal/entropy/v1.0.0/entropy.go
TEXT crypto/internal/entropy/v1%2e0%2e0.sha384Block(SB) /usr/lib/go/src/crypto/internal/entropy/v1.0.0/sha384.go
TEXT crypto/internal/entropy/v1%2e0%2e0.SHA384(SB) /usr/lib/go/src/crypto/internal/entropy/v1.0.0/sha384.go
TEXT crypto/internal/entropy/v1%2e0%2e0.(*source).Sample(SB) /usr/lib/go/src/crypto/internal/entropy/v1.0.0/entropy.go
TEXT crypto/internal/fips140/aes.(*Block).BlockSize(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes.go
TEXT crypto/internal/fips140/aes.(*CBCDecrypter).CryptBlocks(SB) /usr/lib/go/src/crypto/internal/fips140/aes/cbc.go
TEXT crypto/internal/fips140/aes.(*CBCEncrypter).CryptBlocks(SB) /usr/lib/go/src/crypto/internal/fips140/aes/cbc.go
TEXT crypto/internal/fips140/aes.cryptBlocksDecGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/aes/cbc.go
TEXT crypto/internal/fips140/aes.cryptBlocksEncGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/aes/cbc.go
TEXT crypto/internal/fips140/aes.ctrBlocks1Asm.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr_amd64.s
TEXT crypto/internal/fips140/aes.ctrBlocks1(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr_asm.go
TEXT crypto/internal/fips140/aes.ctrBlocks2Asm.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr_amd64.s
TEXT crypto/internal/fips140/aes.ctrBlocks2(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr_asm.go
TEXT crypto/internal/fips140/aes.ctrBlocks4Asm.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr_amd64.s
TEXT crypto/internal/fips140/aes.ctrBlocks4(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr_asm.go
TEXT crypto/internal/fips140/aes.ctrBlocks8Asm.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr_amd64.s
TEXT crypto/internal/fips140/aes.ctrBlocks8(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr_asm.go
TEXT crypto/internal/fips140/aes.ctrBlocks(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr.go
TEXT crypto/internal/fips140/aes.(*CTR).XORKeyStreamAt(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr.go
TEXT crypto/internal/fips140/aes.(*CTR).XORKeyStream(SB) /usr/lib/go/src/crypto/internal/fips140/aes/ctr.go
TEXT crypto/internal/fips140/aes.decryptBlockAsm.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_amd64.s
TEXT crypto/internal/fips140/aes.decryptBlockGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_generic.go
TEXT crypto/internal/fips140/aes.decryptBlock(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_asm.go
TEXT crypto/internal/fips140/aes.encryptBlockAsm.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_amd64.s
TEXT crypto/internal/fips140/aes.encryptBlockGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_generic.go
TEXT crypto/internal/fips140/aes.encryptBlock(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_asm.go
TEXT crypto/internal/fips140/aes.expandKeyAsm.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_amd64.s
TEXT crypto/internal/fips140/aes.expandKeyGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_generic.go
TEXT crypto/internal/fips140/aes/gcm.(*CMAC).deriveSubkeys(SB) /usr/lib/go/src/crypto/internal/fips140/aes/gcm/cmac.go
TEXT crypto/internal/fips140/aes/gcm.(*CMAC).MAC(SB) /usr/lib/go/src/crypto/internal/fips140/aes/gcm/cmac.go
TEXT crypto/internal/fips140/aes/gcm.(*CounterKDF).DeriveKey(SB) /usr/lib/go/src/crypto/internal/fips140/aes/gcm/ctrkdf.go
TEXT crypto/internal/fips140/aes/gcm.init.0.func1(SB) /usr/lib/go/src/crypto/internal/fips140/aes/gcm/cast.go
TEXT crypto/internal/fips140/aes/gcm.init.0(SB) /usr/lib/go/src/crypto/internal/fips140/aes/gcm/cast.go
TEXT crypto/internal/fips140/aes/gcm.init.1(SB) /usr/lib/go/src/crypto/internal/fips140/aes/gcm/gcm_asm.go
TEXT crypto/internal/fips140/aes/gcm.init(SB) <autogenerated>
TEXT crypto/internal/fips140/aes.init.0(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_asm.go
TEXT crypto/internal/fips140/aes.init.1.func1(SB) /usr/lib/go/src/crypto/internal/fips140/aes/cast.go
TEXT crypto/internal/fips140/aes.init.1(SB) /usr/lib/go/src/crypto/internal/fips140/aes/cast.go
TEXT crypto/internal/fips140/aes.init(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_asm.go
TEXT crypto/internal/fips140/aes.(*KeySizeError).Error(SB) <autogenerated>
TEXT crypto/internal/fips140/aes.KeySizeError.Error(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes.go
TEXT crypto/internal/fips140/aes.newBlock(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes_asm.go
TEXT crypto/internal/fips140/aes.newOutlined(SB) /usr/lib/go/src/crypto/internal/fips140/aes/aes.go
TEXT crypto/internal/fips140.CAST(SB) /usr/lib/go/src/crypto/internal/fips140/cast.go
TEXT crypto/internal/fips140/check.init.0(SB) /usr/lib/go/src/crypto/internal/fips140/check/check.go
TEXT crypto/internal/fips140deps/cpu.init(SB) /usr/lib/go/src/crypto/internal/fips140deps/cpu/cpu.go
TEXT crypto/internal/fips140deps/time.monoTime(SB) /usr/lib/go/src/runtime/time.go
TEXT crypto/internal/fips140/drbg.(*Counter).Generate(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/ctrdrbg.go
TEXT crypto/internal/fips140/drbg.(*Counter).Reseed(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/ctrdrbg.go
TEXT crypto/internal/fips140/drbg.(*Counter).update(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/ctrdrbg.go
TEXT crypto/internal/fips140/drbg.getEntropy(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/entropy_fips140.go
TEXT crypto/internal/fips140/drbg.init.0.func1(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/cast.go
TEXT crypto/internal/fips140/drbg.init.0(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/cast.go
TEXT crypto/internal/fips140/drbg.init.func1(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/rand.go
TEXT crypto/internal/fips140/drbg.init(SB) <autogenerated>
TEXT crypto/internal/fips140/drbg.NewCounter(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/ctrdrbg.go
TEXT crypto/internal/fips140/drbg.Read.func1(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/rand.go
TEXT crypto/internal/fips140/drbg.Read(SB) /usr/lib/go/src/crypto/internal/fips140/drbg/rand.go
TEXT crypto/internal/fips140.fatal(SB) /usr/lib/go/src/runtime/panic.go
TEXT crypto/internal/fips140.getIndicator(SB) /usr/lib/go/src/runtime/runtime1.go
TEXT crypto/internal/fips140/hmac.(*HMAC).BlockSize(SB) /usr/lib/go/src/crypto/internal/fips140/hmac/hmac.go
TEXT crypto/internal/fips140/hmac.(*HMAC).Reset(SB) /usr/lib/go/src/crypto/internal/fips140/hmac/hmac.go
TEXT crypto/internal/fips140/hmac.(*HMAC).Sum(SB) /usr/lib/go/src/crypto/internal/fips140/hmac/hmac.go
TEXT crypto/internal/fips140/hmac.(*HMAC).Write(SB) /usr/lib/go/src/crypto/internal/fips140/hmac/hmac.go
TEXT crypto/internal/fips140/hmac.init.0.func1(SB) /usr/lib/go/src/crypto/internal/fips140/hmac/cast.go
TEXT crypto/internal/fips140/hmac.init.0(SB) /usr/lib/go/src/crypto/internal/fips140/hmac/cast.go
TEXT crypto/internal/fips140/hmac.New[go.shape.*uint8].func1.1(SB) /usr/lib/go/src/crypto/internal/fips140/hmac/hmac.go
TEXT crypto/internal/fips140/hmac.New[go.shape.*uint8].func1(SB) /usr/lib/go/src/crypto/internal/fips140/hmac/hmac.go
TEXT crypto/internal/fips140/hmac.New[go.shape.*uint8](SB) /usr/lib/go/src/crypto/internal/fips140/hmac/hmac.go
TEXT crypto/internal/fips140.init.0(SB) /usr/lib/go/src/crypto/internal/fips140/fips140.go
TEXT crypto/internal/fips140.init(SB) <autogenerated>
TEXT crypto/internal/fips140.RecordApproved(SB) /usr/lib/go/src/crypto/internal/fips140/indicator.go
TEXT crypto/internal/fips140.setIndicator(SB) /usr/lib/go/src/runtime/runtime1.go
TEXT crypto/internal/fips140/sha256.blockAVX2.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256block_amd64.s
TEXT crypto/internal/fips140/sha256.blockGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256block.go
TEXT crypto/internal/fips140/sha256.block(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256block_amd64.go
TEXT crypto/internal/fips140/sha256.blockSHANI.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256block_amd64.s
TEXT crypto/internal/fips140/sha256.(*Digest).AppendBinary(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256.go
TEXT crypto/internal/fips140/sha256.(*Digest).BlockSize(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256.go
TEXT crypto/internal/fips140/sha256.(*Digest).checkSum(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256.go
TEXT crypto/internal/fips140/sha256.(*Digest).MarshalBinary(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256.go
TEXT crypto/internal/fips140/sha256.(*Digest).Reset(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256.go
TEXT crypto/internal/fips140/sha256.(*Digest).Sum(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256.go
TEXT crypto/internal/fips140/sha256.(*Digest).UnmarshalBinary(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256.go
TEXT crypto/internal/fips140/sha256.(*Digest).Write(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256.go
TEXT crypto/internal/fips140/sha256.init.0.func1(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/cast.go
TEXT crypto/internal/fips140/sha256.init.0(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/cast.go
TEXT crypto/internal/fips140/sha256.init.1(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256block_amd64.go
TEXT crypto/internal/fips140/sha256.init(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256block_amd64.go
TEXT crypto/internal/fips140/sha256.New(SB) /usr/lib/go/src/crypto/internal/fips140/sha256/sha256.go
TEXT crypto/internal/fips140/sha3.bytepadWrite(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/shake.go
TEXT crypto/internal/fips140/sha3.(*Digest).padAndPermute(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/sha3.go
TEXT crypto/internal/fips140/sha3.(*Digest).readGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/sha3.go
TEXT crypto/internal/fips140/sha3.(*Digest).sumGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/sha3.go
TEXT crypto/internal/fips140/sha3.(*Digest).Sum(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/sha3.go
TEXT crypto/internal/fips140/sha3.(*Digest).writeGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/sha3.go
TEXT crypto/internal/fips140/sha3.(*Digest).Write(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/sha3.go
TEXT crypto/internal/fips140/sha3.init.0.func1(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/cast.go
TEXT crypto/internal/fips140/sha3.init.0(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/cast.go
TEXT crypto/internal/fips140/sha3.keccakF1600.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/sha3_amd64.s
TEXT crypto/internal/fips140/sha3.newCShake128(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/shake.go
TEXT crypto/internal/fips140/sha3.newCShake(SB) /usr/lib/go/src/crypto/internal/fips140/sha3/shake.go
TEXT crypto/internal/fips140/sha512.blockAVX2.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512block_amd64.s
TEXT crypto/internal/fips140/sha512.blockGeneric(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512block.go
TEXT crypto/internal/fips140/sha512.block(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512block_amd64.go
TEXT crypto/internal/fips140/sha512.(*Digest).checkSum(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512.go
TEXT crypto/internal/fips140/sha512.(*Digest).Reset(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512.go
TEXT crypto/internal/fips140/sha512.(*Digest).Sum(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512.go
TEXT crypto/internal/fips140/sha512.(*Digest).Write(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512.go
TEXT crypto/internal/fips140/sha512.init.0.func1(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512block_amd64.go
TEXT crypto/internal/fips140/sha512.init.0(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512block_amd64.go
TEXT crypto/internal/fips140/sha512.init.1(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512block_amd64.go
TEXT crypto/internal/fips140/sha512.init(SB) /usr/lib/go/src/crypto/internal/fips140/sha512/sha512block_amd64.go
TEXT crypto/internal/fips140/subtle.xorBytes.abi0(SB) /usr/lib/go/src/crypto/internal/fips140/subtle/xor_amd64.s
TEXT crypto/internal/fips140/subtle.XORBytes(SB) /usr/lib/go/src/crypto/internal/fips140/subtle/xor.go
TEXT crypto/internal/impl.Register(SB) /usr/lib/go/src/crypto/internal/impl/impl.go
TEXT crypto/internal/rand.(*reader).Read(SB) <autogenerated>
TEXT crypto/internal/rand.reader.Read(SB) /usr/lib/go/src/crypto/internal/rand/rand.go
TEXT crypto/internal/sysrand.fatal(SB) /usr/lib/go/src/runtime/panic.go
TEXT crypto/internal/sysrand.Read.deferwrap1(SB) /usr/lib/go/src/crypto/internal/sysrand/rand.go
TEXT crypto/internal/sysrand.read(SB) /usr/lib/go/src/crypto/internal/sysrand/rand_getrandom.go
TEXT crypto/internal/sysrand.Read(SB) /usr/lib/go/src/crypto/internal/sysrand/rand.go
TEXT crypto/internal/sysrand.urandomRead.func1(SB) /usr/lib/go/src/crypto/internal/sysrand/rand.go
TEXT crypto/internal/sysrand.urandomRead(SB) /usr/lib/go/src/crypto/internal/sysrand/rand.go
TEXT crypto/internal/sysrand.warnBlocked(SB) /usr/lib/go/src/crypto/internal/sysrand/rand.go
TEXT crypto/rand.fatal(SB) /usr/lib/go/src/runtime/panic.go
TEXT crypto/rand.init(SB) <autogenerated>
TEXT crypto/rand.Read(SB) /usr/lib/go/src/crypto/rand/rand.go
Hieruit volgt dat de volgende elementen worden meegeleverd:
- Een bizarre 'voodoo magic' userspace entropy-collector.
- Een gespecialiseerde SHA384-implementatie voor deze entropy-collector.
- Een AES-implementatie.
- Een AES-NI versnelde AES-implementatie.
- Een CTR-implementatie voor AES.
- Een GCM-implementatie voor AES.
- Code voor CPU-detectie.
- Een implementatie van een FIPS-gespecificeerd DRBG-algoritme.
- Een HMAC-implementatie.
- Een SHA256-implementatie.
- Een AVX2-versnelde SHA256-implementatie.
- Een SHA3-implementatie (inclusief cSHAKE).
- Een AVX2-versnelde SHA3-implementatie.
- Een SHA512-implementatie.
- Diverse generieke XOR-bytes routines.
- De eigenlijke syscall-wrappers hiervoor (
crypto/internal/sysrand en crypto/rand).
Dit lijkt me overdreven. Hoewel ik begrijp dat sommige gebruikers gedwongen zijn FIPS-RNG te gebruiken, zou dit in een eigen hoek moeten worden geplaatst en niet standaard in elke Go-binary worden gecompileerd die crypto/rand gebruikt, zeker niet als het niet wordt gebruikt. Dit is een enorme hoeveelheid extra code.
Overwegingen
Zoals eerder vermeld, wordt dit alles beheerd door het lid fips140.Enabled, dat wordt aangestuurd door GODEBUG. Ik stel voor om fips140.Enabled te veranderen van een var naar een const, zodat de compiler de ongebruikte code kan verwijderen. Bepaalde complexe afhankelijkheidsketens kunnen vervolgens worden opgelost door de fips140 build-tag te gebruiken in specifieke bestanden. Dit betekent dat alle aanroepen nog steeds via FIPS140-trampolines verlopen, maar de eigenlijke algoritmen en overbodige code worden verwijderd. De trampolines kunnen bovendien grotendeels worden geïnlined.
Ik heb hierover informeel gesproken met @FiloSottile, die zorgen uitte over de impact op testen en CI. Een deel van dit voorstel omvat daarom het herzien van de tests, zodat onderdelen indien nodig opnieuw worden gecompileerd. De huidige CL-stack doet dit op een vrij nette manier.
Voorstel
Concreet stelt dit voorstel een nieuwe standaardwaarde voor: GOFIPS140=disabled. Dit houdt in dat binaries geen FIPS-specifieke paden (zoals de RNG en diverse extra vertakkingen) compileren.
De onderstaande tabel toont de wijzigingen in de GOFIPS140-variabele:
| Waarde | Voorheen | Na wijziging |
| Niet ingesteld | Standaard 'uit' | Standaard 'disabled' |
| disabled | Ongeldig | FIPS-modus niet beschikbaar; fips140.Enabled is const false |
| off | FIPS-ondersteuning inbegrepen, uitgeschakeld bij opstarten | Ongewijzigd |
| latest | Huidige module, standaard ingeschakeld | Ongewijzigd |
| certified | Gecertificeerde snapshot, standaard ingeschakeld | Ongewijzigd |
| inprocess | Snapshot in certificeringsproces, standaard ingeschakeld | Ongewijzigd |
| Versienummer | Gespecificeerde snapshot, standaard ingeschakeld | Ongewijzigd |
Implementatie
Er is een reeks CL's (Change Lists) beschikbaar op https://go-review.googlesource.com/c/go/+/836445 die dit implementeren en het testen automatiseren om de toekomstige onderhoudslast te verminderen.