mirror of
https://github.com/slackhq/nebula.git
synced 2026-07-02 11:30:29 +02:00
WIP
This commit is contained in:
@@ -188,15 +188,20 @@ build/linux-arm64-boringcrypto/%: LDFLAGS += -checklinkname=0
|
|||||||
|
|
||||||
# fips140
|
# fips140
|
||||||
build/linux-amd64-fips140/%: GOENV += GOFIPS140=v1.0.0
|
build/linux-amd64-fips140/%: GOENV += GOFIPS140=v1.0.0
|
||||||
build/linux-amd64-fips140/%: LDFLAGS += -checklinkname=0 -X runtime.godebugDefault=fips140=only
|
build/linux-amd64-fips140/%: LDFLAGS += -X runtime.godebugDefault=fips140=only
|
||||||
|
build/linux-amd64-fips140/%: BUILD_ARGS += -tags fips140
|
||||||
build/linux-arm64-fips140/%: GOENV += GOFIPS140=v1.0.0
|
build/linux-arm64-fips140/%: GOENV += GOFIPS140=v1.0.0
|
||||||
build/linux-arm64-fips140/%: LDFLAGS += -checklinkname=0 -X runtime.godebugDefault=fips140=only
|
build/linux-arm64-fips140/%: LDFLAGS += -X runtime.godebugDefault=fips140=only
|
||||||
|
build/linux-arm64-fips140/%: BUILD_ARGS += -tags fips140
|
||||||
build/darwin-arm64-fips140/%: GOENV += GOFIPS140=v1.0.0
|
build/darwin-arm64-fips140/%: GOENV += GOFIPS140=v1.0.0
|
||||||
build/darwin-arm64-fips140/%: LDFLAGS += -checklinkname=0 -X runtime.godebugDefault=fips140=only
|
build/darwin-arm64-fips140/%: LDFLAGS += -X runtime.godebugDefault=fips140=only
|
||||||
|
build/darwin-arm64-fips140/%: BUILD_ARGS += -tags fips140
|
||||||
build/windows-amd64-fips140/%: GOENV += GOFIPS140=v1.0.0
|
build/windows-amd64-fips140/%: GOENV += GOFIPS140=v1.0.0
|
||||||
build/windows-amd64-fips140/%: LDFLAGS += -checklinkname=0 -X runtime.godebugDefault=fips140=only
|
build/windows-amd64-fips140/%: LDFLAGS += -X runtime.godebugDefault=fips140=only
|
||||||
|
build/windows-amd64-fips140/%: BUILD_ARGS += -tags fips140
|
||||||
build/windows-arm64-fips140/%: GOENV += GOFIPS140=v1.0.0
|
build/windows-arm64-fips140/%: GOENV += GOFIPS140=v1.0.0
|
||||||
build/windows-arm64-fips140/%: LDFLAGS += -checklinkname=0 -X runtime.godebugDefault=fips140=only
|
build/windows-arm64-fips140/%: LDFLAGS += -X runtime.godebugDefault=fips140=only
|
||||||
|
build/windows-arm64-fips140/%: BUILD_ARGS += -tags fips140
|
||||||
|
|
||||||
build/%/nebula: .FORCE
|
build/%/nebula: .FORCE
|
||||||
GOOS=$(firstword $(subst -, , $*)) \
|
GOOS=$(firstword $(subst -, , $*)) \
|
||||||
@@ -280,8 +285,8 @@ endif
|
|||||||
fips140:
|
fips140:
|
||||||
@echo > $(NULL_FILE)
|
@echo > $(NULL_FILE)
|
||||||
$(eval GOENV += GOFIPS140=v1.0.0)
|
$(eval GOENV += GOFIPS140=v1.0.0)
|
||||||
$(eval LDFLAGS += -checklinkname=0 -X runtime.godebugDefault=fips140=only)
|
$(eval LDFLAGS += -X runtime.godebugDefault=fips140=only)
|
||||||
$(eval TEST_FLAGS += -ldflags -checklinkname=0)
|
$(eval BUILD_ARGS += -tags fips140)
|
||||||
$(eval TEST_ENV += $(GOENV))
|
$(eval TEST_ENV += $(GOENV))
|
||||||
ifeq ($(words $(MAKECMDGOALS)),1)
|
ifeq ($(words $(MAKECMDGOALS)),1)
|
||||||
@$(MAKE) fips140 ${.DEFAULT_GOAL} --no-print-directory
|
@$(MAKE) fips140 ${.DEFAULT_GOAL} --no-print-directory
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build fips140v1.0 || fips140v1.26
|
//go:build fips140
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build fips140v1.0 || fips140v1.26
|
//go:build fips140
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build fips140v1.0 || fips140v1.26
|
//go:build fips140
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func NewCipherState(s *noise.CipherState, cipherFunc noise.CipherFunc) CipherSta
|
|||||||
return cs
|
return cs
|
||||||
}
|
}
|
||||||
switch cipherFunc.CipherName() {
|
switch cipherFunc.CipherName() {
|
||||||
case CipherAESGCM.CipherName():
|
case noise.CipherAESGCM.CipherName():
|
||||||
return NewCipherStateAESGCM(s)
|
return NewCipherStateAESGCM(s)
|
||||||
case noise.CipherChaChaPoly.CipherName():
|
case noise.CipherChaChaPoly.CipherName():
|
||||||
return NewCipherStateChaChaPoly(s)
|
return NewCipherStateChaChaPoly(s)
|
||||||
|
|||||||
+29
-21
@@ -1,3 +1,5 @@
|
|||||||
|
//go:build !boringcrypto
|
||||||
|
|
||||||
package noiseutil
|
package noiseutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -11,9 +13,10 @@ import (
|
|||||||
"github.com/flynn/noise"
|
"github.com/flynn/noise"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TODO: Use NewGCMWithCounterNonce once available:
|
// TODO: Use NewGCMWithCounterNonce or NewGCMForQUIC once available:
|
||||||
// - https://github.com/golang/go/issues/73110
|
// - https://github.com/golang/go/issues/73110
|
||||||
// Using tls.aeadAESGCM gives us the TLS 1.2 GCM, which also verifies
|
// - https://github.com/golang/go/issues/79219
|
||||||
|
// Using tls.aeadAESGCMTLS13 gives us the TLS 1.3 GCM, which also verifies
|
||||||
// that the nonce is strictly increasing.
|
// that the nonce is strictly increasing.
|
||||||
//
|
//
|
||||||
//go:linkname aeadAESGCMTLS13 crypto/tls.aeadAESGCMTLS13
|
//go:linkname aeadAESGCMTLS13 crypto/tls.aeadAESGCMTLS13
|
||||||
@@ -28,7 +31,7 @@ func (c cipherFn) Cipher(k [32]byte) noise.Cipher { return c.fn(k) }
|
|||||||
func (c cipherFn) CipherName() string { return c.name }
|
func (c cipherFn) CipherName() string { return c.name }
|
||||||
|
|
||||||
// CipherAESGCM is the AES256-GCM AEAD cipher (using aeadAESGCM when fips140 is enabled)
|
// CipherAESGCM is the AES256-GCM AEAD cipher (using aeadAESGCM when fips140 is enabled)
|
||||||
var CipherAESGCM noise.CipherFunc = cipherFn{cipherAESGCMFIPS140, "AESGCM"}
|
var CipherAESGCMFIPS140 noise.CipherFunc = cipherFn{cipherAESGCMFIPS140, "AESGCM"}
|
||||||
|
|
||||||
// tls.aeadAESGCMTLS13 uses a 4 byte static prefix and an 8 byte XOR mask
|
// tls.aeadAESGCMTLS13 uses a 4 byte static prefix and an 8 byte XOR mask
|
||||||
var emptyPrefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
var emptyPrefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
@@ -36,11 +39,11 @@ var emptyNonce = []byte{0, 0, 0, 0, 0, 0, 0, 0}
|
|||||||
|
|
||||||
func cipherAESGCMFIPS140(k [32]byte) noise.Cipher {
|
func cipherAESGCMFIPS140(k [32]byte) noise.Cipher {
|
||||||
gcm := aeadAESGCMTLS13(k[:], emptyPrefix)
|
gcm := aeadAESGCMTLS13(k[:], emptyPrefix)
|
||||||
return aeadCipher{
|
return &aeadCipher{
|
||||||
gcm,
|
AEAD: gcm,
|
||||||
false,
|
ready: false,
|
||||||
func(n uint64) []byte {
|
nonce: func(n uint64) []byte {
|
||||||
// tls.aeadAESGCM uses a 4 byte static prefix and an 8 byte nonce
|
// tls.aeadAESGCMTLS13 uses a 4 byte static prefix and an 8 byte nonce
|
||||||
var nonce [8]byte
|
var nonce [8]byte
|
||||||
binary.BigEndian.PutUint64(nonce[:], n)
|
binary.BigEndian.PutUint64(nonce[:], n)
|
||||||
return nonce[:]
|
return nonce[:]
|
||||||
@@ -48,37 +51,42 @@ func cipherAESGCMFIPS140(k [32]byte) noise.Cipher {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type aeadCipher struct {
|
func (c *aeadCipher) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
||||||
cipher.AEAD
|
// runtime.Breakpoint()
|
||||||
initialized bool
|
if !c.ready {
|
||||||
nonce func(uint64) []byte
|
// crypto/tls.aeadAESGCMTLS13 expected that the first call to Seal
|
||||||
}
|
// is with a counter of `0`, this is how it extracts the nonce mask.
|
||||||
|
// We can clean this up in the future when NewGCMWithCounterNonce or
|
||||||
func (c aeadCipher) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
|
// NewGCMForQUIC are available:
|
||||||
if !c.initialized {
|
|
||||||
if !bytes.Equal(emptyNonce, nonce) {
|
if !bytes.Equal(emptyNonce, nonce) {
|
||||||
c.AEAD.Seal([]byte{}, emptyNonce, []byte{}, []byte{})
|
c.AEAD.Seal([]byte{}, emptyNonce, []byte{}, []byte{})
|
||||||
}
|
}
|
||||||
c.initialized = true
|
c.ready = true
|
||||||
}
|
}
|
||||||
return c.AEAD.Seal(dst, nonce, plaintext, additionalData)
|
return c.AEAD.Seal(dst, nonce, plaintext, additionalData)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c aeadCipher) Encrypt(out []byte, n uint64, ad, plaintext []byte) []byte {
|
type aeadCipher struct {
|
||||||
|
cipher.AEAD
|
||||||
|
ready bool
|
||||||
|
nonce func(uint64) []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *aeadCipher) Encrypt(out []byte, n uint64, ad, plaintext []byte) []byte {
|
||||||
return c.Seal(out, c.nonce(n), plaintext, ad)
|
return c.Seal(out, c.nonce(n), plaintext, ad)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c aeadCipher) Decrypt(out []byte, n uint64, ad, ciphertext []byte) ([]byte, error) {
|
func (c *aeadCipher) Decrypt(out []byte, n uint64, ad, ciphertext []byte) ([]byte, error) {
|
||||||
return c.Open(out, c.nonce(n), ciphertext, ad)
|
return c.Open(out, c.nonce(n), ciphertext, ad)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c aeadCipher) EncryptDanger(out, ad, plaintext []byte, n uint64, nb []byte) ([]byte, error) {
|
func (c *aeadCipher) EncryptDanger(out, ad, plaintext []byte, n uint64, nb []byte) ([]byte, error) {
|
||||||
binary.BigEndian.PutUint64(nb[4:], n)
|
binary.BigEndian.PutUint64(nb[4:], n)
|
||||||
out = c.Seal(out, nb[4:], plaintext, ad)
|
out = c.Seal(out, nb[4:], plaintext, ad)
|
||||||
return out, nil
|
return out, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c aeadCipher) DecryptDanger(out, ad, ciphertext []byte, n uint64, nb []byte) ([]byte, error) {
|
func (c *aeadCipher) DecryptDanger(out, ad, ciphertext []byte, n uint64, nb []byte) ([]byte, error) {
|
||||||
binary.BigEndian.PutUint64(nb[4:], n)
|
binary.BigEndian.PutUint64(nb[4:], n)
|
||||||
return c.Open(out, nb[4:], ciphertext, ad)
|
return c.Open(out, nb[4:], ciphertext, ad)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,10 @@ func TestNewAESGCM(t *testing.T) {
|
|||||||
assert.Equal(t, expected, dst)
|
assert.Equal(t, expected, dst)
|
||||||
|
|
||||||
// We expect this to fail since we are re-encrypting with a repeat IV
|
// We expect this to fail since we are re-encrypting with a repeat IV
|
||||||
assert.PanicsWithValue(t, "crypto/cipher: counter decreased or remained the same", func() {
|
// TODO: the error message has changed between fips module versions, best way to verify it?
|
||||||
|
// assert.PanicsWithValue(t, "crypto/cipher: counter decreased", func() {
|
||||||
|
// assert.PanicsWithValue(t, "crypto/cipher: counter decreased or remained the same", func() {
|
||||||
|
assert.Panics(t, func() {
|
||||||
dst = aead.Seal([]byte{}, iv, plaintext, aad)
|
dst = aead.Seal([]byte{}, iv, plaintext, aad)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-2
@@ -4,10 +4,20 @@ package noiseutil
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/fips140"
|
"crypto/fips140"
|
||||||
|
|
||||||
|
"github.com/flynn/noise"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EncryptLockNeeded indicates if calls to Encrypt need a lock
|
// EncryptLockNeeded indicates if calls to Encrypt need a lock
|
||||||
var EncryptLockNeeded = fips140.Enabled()
|
var EncryptLockNeeded = fips140.Enabled()
|
||||||
|
|
||||||
// CipherAESGCM is the standard noise.CipherAESGCM when boringcrypto is not enabled
|
var CipherAESGCM noise.CipherFunc = initAESGCM()
|
||||||
// var CipherAESGCM noise.CipherFunc = noise.CipherAESGCM
|
|
||||||
|
func initAESGCM() noise.CipherFunc {
|
||||||
|
if fips140.Enabled() {
|
||||||
|
return CipherAESGCMFIPS140
|
||||||
|
} else {
|
||||||
|
return noise.CipherAESGCM
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user