Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

boringcrypto: SHA functions do not use FIPS compliant openssl APIs #66520

Closed
evanskinner opened this issue Mar 25, 2024 · 10 comments
Closed

boringcrypto: SHA functions do not use FIPS compliant openssl APIs #66520

evanskinner opened this issue Mar 25, 2024 · 10 comments

Comments

@evanskinner
Copy link

Go version

go1.20.12

Output of go env in your module/workspace:

GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/root/.cache/go-build"
GOENV="/root/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/tmp/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/tmp/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/lib/golang"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/golang/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.20.12"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build2938776592=/tmp/go-build -gno-record-gcc-switches"

What did you do?

The functions in sha.go are all using the deprecated low level API calls in openssl. These do not go via the fips provider and so are not FIPS compliant. See:

_goboringcrypto_SHA1_Init(&ctx);
for an example. Instead of doing

SHA1_Init
SHA1_Update
SHA1_Final

We should be doing something like:

    const EVP_MD *md = EVP_get_digestbyname("sha256");
    if (md == NULL) {
        printf("Unknown message digest %s\n", "sha256");
        exit(1);
    }
    EVP_MD_CTX *ctx = EVP_MD_CTX_new();
        if (!EVP_DigestInit_ex(ctx, md, NULL)) {
        printf("Message digest initialization failed.\n");
	ERR_print_errors_fp (stderr);
        EVP_MD_CTX_free(ctx);
        exit(1);
    }
    EVP_DigestUpdate(ctx, data, strlen(data));
    EVP_DigestFinal_ex(ctx, md_value, &md_len);

This uses the high level EVP_ API and will be FIPS compliant. On the page (https://www.openssl.org/docs/manmaster/man7/fips_module.html):

Applications written to use the OpenSSL 3.0 FIPS module should not use any legacy APIs or features that avoid the FIPS module. Specifically this includes:

Low level cryptographic APIs (use the high level APIs, such as EVP, instead)

Also see https://github.com/openssl/openssl/blob/a4cbffcd8998180b98bb9f7ce6065ed37d079d8b/doc/man7/ossl-guide-migration.pod#L1105 where openssl say not to use functions such as SHA1_Init etc and instead use EVP. Apparently there are some convinience functions as well ..or the quick one-shot L<EVP_Q_digest(3)>

Note this bug is a follow-on from #66513 where I have removed the references about md5 that muddied the waters in the original bug report.

What did you see happen?

All covered in initial section

What did you expect to see?

All covered in initial section

@ianlancetaylor
Copy link
Member

CC @golang/security

@FiloSottile
Copy link
Contributor

These do not go via the fips provider and so are not FIPS compliant.

Applications written to use the OpenSSL 3.0 FIPS module

Go+BoringCrypto doesn't use the OpenSSL 3.0 FIPS module. Is this the case for BoringCrypto as well?

@evanskinner
Copy link
Author

evanskinner commented Mar 25, 2024

I forgot to mention I am using the go-toolset on Redhat, but the boringcrypto code that calls into openssl is the same, and if openssl is running in FIPS mode (Redhat fips-mode-setup enable so kernel has fips=1 and openssl is setup to use the fips module) I think that means that openssl C API calls in boringcrypto should aim to be using the high level openssl API calls so that they go via the openssl fips provider.

The redhat tool fips-mode-setup enable essentially does what openssl details in the Making all applications use the FIPS module by default secition in https://www.openssl.org/docs/man3.0/man7/fips_module.html. Or at least that is my understanding of it.

@evanskinner
Copy link
Author

evanskinner commented Mar 25, 2024

Also when I ran my go code that did:

		result2 := sha1.Sum([]byte("hash me"))
		fmt.Printf("%x\n", result2)

like this: LD_DEBUG=symbols /tmp/test fips-self-test
I got:

...
   3880446:	calling init: /usr/lib64/ossl-modules/fips.so
   3880446:	
   3880446:	symbol=OSSL_provider_init;  lookup in file=/usr/lib64/ossl-modules/fips.so [0]
   3880446:	symbol=pthread_mutex_init;  lookup in file=/tmp/test [0]
   3880446:	symbol=pthread_mutex_init;  lookup in file=/lib64/libresolv.so.2 [0]
   3880446:	symbol=pthread_mutex_init;  lookup in file=/lib64/libc.so.6 [0]
   3880446:	symbol=SHA1_Init;  lookup in file=/tmp/test [0]
   3880446:	symbol=SHA1_Init;  lookup in file=/lib64/libresolv.so.2 [0]
   3880446:	symbol=SHA1_Init;  lookup in file=/lib64/libc.so.6 [0]
   3880446:	symbol=SHA1_Init;  lookup in file=/lib64/ld-linux-x86-64.so.2 [0]
   3880446:	symbol=SHA1_Init;  lookup in file=/lib64/libcrypto.so.3 [0]
   3880446:	symbol=SHA1_Update;  lookup in file=/tmp/test [0]
   3880446:	symbol=SHA1_Update;  lookup in file=/lib64/libresolv.so.2 [0]
   3880446:	symbol=SHA1_Update;  lookup in file=/lib64/libc.so.6 [0]
   3880446:	symbol=SHA1_Update;  lookup in file=/lib64/ld-linux-x86-64.so.2 [0]
   3880446:	symbol=SHA1_Update;  lookup in file=/lib64/libcrypto.so.3 [0]
   3880446:	symbol=SHA1_Final;  lookup in file=/tmp/test [0]
   3880446:	symbol=SHA1_Final;  lookup in file=/lib64/libresolv.so.2 [0]
   3880446:	symbol=SHA1_Final;  lookup in file=/lib64/libc.so.6 [0]
   3880446:	symbol=SHA1_Final;  lookup in file=/lib64/ld-linux-x86-64.so.2 [0]
   3880446:	symbol=SHA1_Final;  lookup in file=/lib64/libcrypto.so.3 [0]

Which shows it is using the FIPS module in openssl

@FiloSottile
Copy link
Contributor

Ah, you are using Red Hat's fork that uses OpenSSL's module. I'm afraid we don't have the bandwidth upstream to handle issues of the downstream forks.

@evanskinner
Copy link
Author

evanskinner commented Mar 25, 2024

@FiloSottile OK np, so the boringcrypto code in this repo does not call into openssl the same way Redhat's does?

Looking at the code it seemed like an issue in the base boringcrypto so I was trying to cut out the middle man and get straight to the source as the code in this repo for the openssl C API calls for SHA are the same as in the Redhat fork.

@FiloSottile
Copy link
Contributor

BoringCrypto APIs diverged a bit from OpenSSL 3.0, and the FIPS module design is very different, so I'm asking whether "SHA1_Init/SHA1_Update/SHA1_Final don't call into the FIPS engine" is true of BoringCrypto. If not, this is a downstream fork issue.

@evanskinner
Copy link
Author

Thanks for the explanation. I will do a bit more digging using standard go and GOEXPERIMENT=boringcrypto at compile time and get back to you, probably tomorrow. Are there any docs you can point me at for how normal boringcrypto mode works please? I'm not sure I fully undersand the difference between standard boringcrypto and Redhat's version.

@seankhliao
Copy link
Member

boringssl only defines SHA1_Init under crypto/fipsmodule/sha
https://github.com/google/boringssl/blob/70b33d39048abaa1c810ad63ace4b05af7b94d15/crypto/fipsmodule/sha/sha1.c#L69 so there's no non fips implementation?

@evanskinner
Copy link
Author

Aaaah. My apologies and thank you both so much for your time. I see now where the standard boringcrypto/ssl and Redhat's version diverge. I was thrown as the function name SHA1_Init is identical to openssl and I hadn't dug into borringssl's code. Closing this as it is invalid and I will raise it on Redhat.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants