From 157f5d141215ec8a77a06a93ee2f9f1376b31811 Mon Sep 17 00:00:00 2001 From: Nuno Diegues Date: Tue, 9 Nov 2021 11:37:51 +0000 Subject: [PATCH] TUN-5277: Ensure cloudflared binary is FIPS compliant on linux amd64 --- Makefile | 46 ++++++++++++++++++++++++---------------------- build-packages.sh | 19 +++++++++++++------ cfsetup.yaml | 3 +-- check-fips.sh | 15 +++++++++++++++ 4 files changed, 53 insertions(+), 30 deletions(-) create mode 100755 check-fips.sh diff --git a/Makefile b/Makefile index 3dfe8dfa..b04fa6b9 100644 --- a/Makefile +++ b/Makefile @@ -3,14 +3,6 @@ MSI_VERSION := $(shell git tag -l --sort=v:refname | grep "w" | tail -1 | cut #MSI_VERSION expects the format of the tag to be: (wX.X.X). Starts with the w character to not break cfsetup. #e.g. w3.0.1 or w4.2.10. It trims off the w character when creating the MSI. -ifeq ($(FIPS), true) - GO_BUILD_TAGS := $(GO_BUILD_TAGS) fips -endif - -ifneq ($(GO_BUILD_TAGS),) - GO_BUILD_TAGS := -tags $(GO_BUILD_TAGS) -endif - ifeq ($(NIGHTLY), true) DEB_PACKAGE_NAME := cloudflared-nightly NIGHTLY_FLAGS := --conflicts cloudflared --replaces cloudflared @@ -19,7 +11,19 @@ else endif DATE := $(shell date -u '+%Y-%m-%d-%H%M UTC') -VERSION_FLAGS := -ldflags='-X "main.Version=$(VERSION)" -X "main.BuildTime=$(DATE)"' +VERSION_FLAGS := -X "main.Version=$(VERSION)" -X "main.BuildTime=$(DATE)" + +LINK_FLAGS := +ifeq ($(FIPS), true) + LINK_FLAGS := -linkmode=external -extldflags=-static $(LINK_FLAGS) + # Prevent linking with libc regardless of CGO enabled or not. + GO_BUILD_TAGS := $(GO_BUILD_TAGS) osusergo netgo fips +endif + +LDFLAGS := -ldflags='$(VERSION_FLAGS) $(LINK_FLAGS)' +ifneq ($(GO_BUILD_TAGS),) + GO_BUILD_TAGS := -tags "$(GO_BUILD_TAGS)" +endif IMPORT_PATH := github.com/cloudflare/cloudflared PACKAGE_DIR := $(CURDIR)/packaging @@ -80,17 +84,15 @@ clean: go clean .PHONY: cloudflared -cloudflared: +cloudflared: ifeq ($(FIPS), true) $(info Building cloudflared with go-fips) - -test -f fips/fips.go && mv fips/fips.go fips/fips.go.linux-amd64 - mv fips/fips.go.linux-amd64 fips/fips.go + cp -f fips/fips.go.linux-amd64 cmd/cloudflared/fips.go endif - - GOOS=$(TARGET_OS) GOARCH=$(TARGET_ARCH) go build -v -mod=vendor $(GO_BUILD_TAGS) $(VERSION_FLAGS) $(IMPORT_PATH)/cmd/cloudflared - + GOOS=$(TARGET_OS) GOARCH=$(TARGET_ARCH) go build -v -mod=vendor $(GO_BUILD_TAGS) $(LDFLAGS) $(IMPORT_PATH)/cmd/cloudflared ifeq ($(FIPS), true) - mv fips/fips.go fips/fips.go.linux-amd64 + rm -f cmd/cloudflared/fips.go + ./check-fips.sh cloudflared endif .PHONY: container @@ -100,10 +102,10 @@ container: .PHONY: test test: vet ifndef CI - go test -v -mod=vendor -race $(VERSION_FLAGS) ./... + go test -v -mod=vendor -race $(LDFLAGS) ./... else @mkdir -p .cover - go test -v -mod=vendor -race $(VERSION_FLAGS) -coverprofile=".cover/c.out" ./... + go test -v -mod=vendor -race $(LDFLAGS) -coverprofile=".cover/c.out" ./... go tool cover -html ".cover/c.out" -o .cover/all.html endif @@ -247,8 +249,8 @@ tunnelrpc-deps: capnp compile -ogo tunnelrpc/tunnelrpc.capnp .PHONY: quic-deps -quic-deps: - which capnp +quic-deps: + which capnp which capnpc-go capnp compile -ogo quic/schema/quic_metadata_protocol.capnp @@ -258,9 +260,9 @@ vet: # go get github.com/sudarshan-reddy/go-sumtype (don't do this in build directory or this will cause vendor issues) # Note: If you have github.com/BurntSushi/go-sumtype then you might have to use the repo above instead # for now because it uses an older version of golang.org/x/tools. - which go-sumtype + which go-sumtype go-sumtype $$(go list -mod=vendor ./...) .PHONY: goimports goimports: - for d in $$(go list -mod=readonly -f '{{.Dir}}' -a ./... | fgrep -v tunnelrpc) ; do goimports -format-only -local github.com/cloudflare/cloudflared -w $$d ; done + for d in $$(go list -mod=readonly -f '{{.Dir}}' -a ./... | fgrep -v tunnelrpc) ; do goimports -format-only -local github.com/cloudflare/cloudflared -w $$d ; done \ No newline at end of file diff --git a/build-packages.sh b/build-packages.sh index 7b4ece82..88b2866a 100755 --- a/build-packages.sh +++ b/build-packages.sh @@ -1,12 +1,15 @@ VERSION=$(git describe --tags --always --dirty="-dev" --match "[0-9][0-9][0-9][0-9].*.*") echo $VERSION + +# Avoid depending on C code since we don't need it. export CGO_ENABLED=0 + # This controls the directory the built artifacts go into export ARTIFACT_DIR=built_artifacts/ mkdir -p $ARTIFACT_DIR windowsArchs=("amd64" "386") export TARGET_OS=windows -for arch in ${windowsArchs[@]}; do +for arch in ${windowsArchs[@]}; do export TARGET_ARCH=$arch make cloudflared-msi mv ./cloudflared.exe $ARTIFACT_DIR/cloudflared-windows-$arch.exe @@ -14,15 +17,20 @@ for arch in ${windowsArchs[@]}; do done -export FIPS=true -linuxArchs=("amd64" "386" "arm" "arm64") +# amd64 is last because we override settings for it +linuxArchs=("386" "arm" "arm64" "amd64") export TARGET_OS=linux -for arch in ${linuxArchs[@]}; do +for arch in ${linuxArchs[@]}; do + if [ "${arch}" = "amd64" ]; then + export FIPS=true + # For BoringCrypto to link, we need CGO enabled. Otherwise compilation fails. + export CGO_ENABLED=1 + fi export TARGET_ARCH=$arch make cloudflared-deb mv cloudflared\_$VERSION\_$arch.deb $ARTIFACT_DIR/cloudflared-linux-$arch.deb - # rpm packages invert the - and _ and use x86_64 instead of amd64. + # rpm packages invert the - and _ and use x86_64 instead of amd64. RPMVERSION=$(echo $VERSION|sed -r 's/-/_/g') RPMARCH=$arch if [ $arch == "amd64" ];then @@ -37,4 +45,3 @@ for arch in ${linuxArchs[@]}; do # finally move the linux binary as well. mv ./cloudflared $ARTIFACT_DIR/cloudflared-linux-$arch done - diff --git a/cfsetup.yaml b/cfsetup.yaml index 383fab86..fb7314b2 100644 --- a/cfsetup.yaml +++ b/cfsetup.yaml @@ -1,5 +1,5 @@ pinned_go: &pinned_go go=1.17-1 -pinned_go_fips: &pinned_go_fips go-boring=1.16.6-6 +pinned_go_fips: &pinned_go_fips go-boring=1.16.6-7 build_dir: &build_dir /cfsetup_build default-flavor: buster @@ -41,7 +41,6 @@ stretch: &stretch - wget https://github.com/sudarshan-reddy/msitools/releases/download/v0.101b/wixl -P /usr/local/bin - chmod a+x /usr/local/bin/wixl post-cache: - - export FIPS=true - ./build-packages.sh github-release-pkgs: build_dir: *build_dir diff --git a/check-fips.sh b/check-fips.sh new file mode 100755 index 00000000..98c05af1 --- /dev/null +++ b/check-fips.sh @@ -0,0 +1,15 @@ +# Pass the path to the executable to check for FIPS compliance +exe=$1 + +if [ "$(go tool nm "${exe}" | grep -c '_Cfunc__goboringcrypto_')" -eq 0 ]; then + # Asserts that executable is using FIPS-compliant boringcrypto + echo "${exe}: missing goboring symbols" >&2 + exit 1 +fi +if [ "$(go tool nm "${exe}" | grep -c 'crypto/internal/boring/sig.FIPSOnly')" -eq 0 ]; then + # Asserts that executable is using FIPS-only schemes + echo "${exe}: missing fipsonly symbols" >&2 + exit 1 +fi + +echo "${exe} is FIPS-compliant"