本文永久链接 – https://tonybai.com/2024/11/16/go-crypto-and-fips-140
在今年3月份,Microsoft Azure团队宣布开设Go开发人员博客,旨在向开发者通报Microsoft在Go领域的最新动态,包括如何在Azure上部署Go工作负载以及与Go编程相关的文章。
然而,经过一段时间的关注,我发现该博客上的大多数文章都呈现出类似下图中的标题格式:
似乎微软在紧跟Go的发布节奏,发布自己维护的fork版本。那么,这些fork版本与上游Go究竟有何不同呢?通过查阅其fork版的README文件,我们可以找到答案:
原来微软的Go分支主要是为了向开发者提供符合FIPS 140-2标准的Go加密库。
近期,Russ Cox也发起了一个新提案,旨在使Go的加密库符合FIPS 140标准,以便能够去除Boring Crypto库。
对于许多对加密领域不太熟悉的读者来说,这可能会引发一系列疑问:什么是FIPS 140标准?Go目前对FIPS 140标准的支持状态如何?新提案将如何影响Go未来对FIPS 140标准的支持?
在这篇文章中,我们就一起了解一下FIPS 140标准、Go对其支持的现状以及未来的支持策略。
FIPS 140(联邦信息处理标准第140号)是美国政府制定的一套计算机安全标准,主要用于规定加密模块的要求。该标准由美国国家标准与技术研究院(NIST)发布,旨在确保用于加密的硬件和软件模块满足一定的安全标准。
FIPS 140标准经历了多个版本的演进:
于1994年发布,2002年撤回。它首次定义了四个安全级别和十一项要求领域。
于2001年发布,考虑了技术的发展和用户反馈,是国际标准ISO/IEC 19790:2006的基础文件。FIPS 140-2仍然在使用,直到2022年4月某些应用程序的测试可以继续进行。FIPS 140-2定义了四个安全级别:
级别1:最低要求,所有组件必须是“生产级”的,且不允许有明显的安全漏洞。
级别2:增加了物理防篡改的要求,要求有角色基础的身份验证。
级别3:要求更高的物理防篡改能力和基于身份的认证,同时要求对模块的关键安全参数接口进行物理或逻辑隔离。
级别4:对物理安全要求更严格,要求能够抵御环境攻击。
在2019年发布,作为FIPS 140-2的继任者,FIPS 140-3对标准进行了更新,使其与国际标准更为一致,并引入了新的安全要求。
FIPS 140认证由加密模块验证计划(CMVP)负责,该计划是NIST与加拿大通信安全局(CSE)共同运营的。认证过程涉及对加密模块的详细测试,确保其符合相应的标准要求。所有使用加密的美国联邦政府部门都必须使用经过FIPS 140认证的模块。
FIPS 140并不保证使用该标准的模块一定是安全的,但它确立了一系列文档和测试要求,确保加密模块在设计和实现上的可靠性。对于希望使用加密模块的用户和开发者来说,确认所使用的模块是否有现有的验证证书是非常重要的。
FIPS 140是美国政府对加密模块的要求,许多公司需要遵守这些标准以满足合规性需求,尤其是一些企业在与美国政府及其他受监管行业的合作中,FIPS合规性变得至关重要,这也是微软为何要建立Go Fork分支满足FIPS合规性,以及Go团队发起尽快让Go加密库满足FIPS合规性的提案的根本原因。随着Go在受监管环境中的采用增加,FIPS合规性将影响Go的吸引力和开发者体验。
那么当前Go密码学包对FIPS的支持是怎样的呢?我们继续往下看。
到目前为止(Go 1.23.x版本),Go原生的crypto包并不具备FIPS认证。并且,在2017年的一个名为”crypto: FIPS 140-2 Certification“的issue中,Go密码学领域的首任技术负责人Adam Langley给出了这样的答复:
从Adam Langley的表述中可以看出,他似乎对FIPS 140这样的官方标准持有一种不屑的态度。同时他也指出对于FIPS 140认证感兴趣的开发者,可以尝试使用dev.boringcrypto分支。
dev.boringcrypto分支是什么呢?它又是如何实现FPIS 140合规的呢?其实思路很简单,那就是:既然我暂时是不合规的,那我就找一个合规的,然后包装一下提供给开发者使用。
那么什么库是合规的呢?BoringSSL,也就是Google fork的OpenSSL库的自维护版本,更精确地一点是BoringSSL库的一部分内容通过了FIPS 140-2认证:
而通过认证的这部分模块被称为BoringCrypto:
Go dev.boringcrypto分支就是通过BoringSSL的binding来实现FIPS 140合规的,通过导入crypto/tls/fipsonly包,可以将所有TLS配置限制为FIPS合规设置,确保使用合规的加密算法。下面是Go 1.23.0中crypto/tls/fipsonly下fipsonly.go的源码,我们可以看到它实际上使用的是crypto/internal/boring下面的合规包:
// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build boringcrypto
// Package fipsonly restricts all TLS configuration to FIPS-approved settings.
//
// The effect is triggered by importing the package anywhere in a program, as in:
//
// import _ "crypto/tls/fipsonly"
//
// This package only exists when using Go compiled with GOEXPERIMENT=boringcrypto.
package fipsonly
// This functionality is provided as a side effect of an import to make
// it trivial to add to an existing program. It requires only a single line
// added to an existing source file, or it can be done by adding a whole
// new source file and not modifying any existing source files.
import (
"crypto/internal/boring/fipstls"
"crypto/internal/boring/sig"
)
func init() {
fipstls.Force()
sig.FIPSOnly()
}
从Go 1.8开始,Go都会在发布大版本时建立对应该大版本的dev.boriingcrypto分支,如下图:
但Go官方在Go 1.18版本之后似乎就不维护这个分支了。微软也恰是从那时(2022年初)开始fork了Go repo并维护自己的fips合规版本,在Linux上,该Fork使用OpenSSL的Go binding进行加密,而在Windows上使用CNG(Cryptography Next Generation)。
注:尽管使用微软的Go工具链构建的应用程序可以在FIPS兼容模式下运行,但这并不意味着自动符合FIPS认证。开发团队需确保使用FIPS合规的加密原语及工作流程。如果无法提供FIPS合规的实现,修改后的加密运行时将回退到Go标准库的加密方法,如使用crypto/md5或非标准nonce大小的AES-GCM等。
由于BoringSSL是C语言的,Go dev.boringcrypto分支势必要依赖cgo,将部分加密包的内部实现替换为通过FIPS 140认证的模块。但这种方案存在许多问题,如内存不安全代码、影响Go版本更新、性能问题和开发体验等。于是就有了文前提到的旨在移除BoringCrypto的Go团队的新提案。
新提案的内容是什么呢?下面我们就来细致看看。
根据Go加密库上一任Tech leader Filippo Valsorda在proposal: crypto: mechanism to enable FIPS mode中的描述,Go团队希望为Go加密库实现FIPS 140-3认证,并允许开发者启用或禁用FIPS模式,以满足合规性要求。
该proposal建议在运行时通过设置GODEBUG标志来启用FIPS模式,新增GODEBUG=fips140选项。并且通过GODEBUG=fips140的值可以控制FIPS模式:
在代码层面,新增crypto/fips140包或放在crypto/internal/fips下,其中包含Enabled() bool函数,用于运行时检查当前是否启用了FIPS模式。
Russ Cox之后在”proposal: cmd/go: add fips140 module selection mechanism“的issue中着重阐述了在Go module层面对fips 140的支持策略,目前仍在更新中,根据Russ Cox 2024.11.11的最新comment,当前设计的策略大致如下:
该环境变量可取值为off、latest、inprocess、certified或v1.X.Y-fips.N,默认值为off。使用go version -m或获取debug.BuildInfo时,可显示新的构建设置GOFIPS140,其值为off、devel或具体的版本号。
- off(默认):使用最新源代码,GODEBUG设置为fips140=off。
- latest:使用最新源代码,GODEBUG设置为fips140=on。
- v1.X.Y-fips.N:使用指定的快照。
- inprocess:使用正在进行FIPS标准认证的版本。
- certified:使用经过NIST的FIPS认证的版本。
用户不可见的API或工具将不会将crypto/internal/fips代码视为module。在运行go list时,crypto/internal/fips/…的包可以来自\$GOROOT/src/crypto/internal/fips/…或module cache中的目录,Module字段将为nil,与标准库其他部分一致。
尽管crypto/internal/fips有语义版本控制的版本集合,但它们与Go模块系统完全分离。存在于lib/fips140中的文件将采用实现定义(implementation-defined)的格式,尽管其格式很可能采用module zip和checksum的形式。
以上策略的实施将增强Go在FIPS 140支持方面的灵活性和可控性,为开发者提供了更清晰的配置选项。通过将FIPS 支持的配置独立于模块系统,开发者可以更方便地管理构建环境,避免潜在的配置冲突。
并且按照Russ Cox的说法,Go团队计划每年进行一次Go加密库的重新验证,以保持模块的合规性和及时更新。
本文探讨了Go语言加密库在FIPS 140标准支持方面的现状及未来发展。FIPS 140是美国政府制定的一套加密模块安全标准,目前的版本为FIPS 140-3,涵盖了最新的安全要求。
我们详细分析了Go加密库的现状,包括通过BoringSSL实现FIPS 140合规的dev.boringcrypto分支,以及微软维护的FIPS 140合规Go Fork版本。此外,Go团队还提出了针对FIPS 140-3认证的新提案,旨在允许开发者在运行时灵活启用或禁用FIPS模式。这一新提案的实施将为Go提供更大的合规灵活性,并为开发者提供清晰的配置选项,从而增强Go在受监管环境中的吸引力和实用性。
目前,关于Go加密库对FIPS 140支持的相关事项仍处于提案阶段,具体思路和实现细节可能会随着进一步的发展而变化。然而,本文通过对FIPS认证的介绍以及Go加密库未来计划的阐述,相信读者已经初步掌握了选择Go加密模块和满足合规性需求的有用信息。
如果你有什么疑问,欢迎在评论区留言,通过讨论碰撞,我们一起进步和成长!
Gopher部落知识星球在2024年将继续致力于打造一个高品质的Go语言学习和交流平台。我们将继续提供优质的Go技术文章首发和阅读体验。同时,我们也会加强代码质量和最佳实践的分享,包括如何编写简洁、可读、可测试的Go代码。此外,我们还会加强星友之间的交流和互动。欢迎大家踊跃提问,分享心得,讨论技术。我会在第一时间进行解答和交流。我衷心希望Gopher部落可以成为大家学习、进步、交流的港湾。让我相聚在Gopher部落,享受coding的快乐! 欢迎大家踊跃加入!
著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。
Gopher Daily(Gopher每日新闻) – https://gopherdaily.tonybai.com
我的联系方式:
商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。
© 2024, bigwhite. 版权所有.