背景NationalSecret是NationalCommercialCryptography的缩写。国家密码管理局制定算法标准,同时也制定了大量的产品和接口规范以及应用场景。随着近年来外部国际贸易冲突和技术封锁,内部互联网的快速发展,物联网领域的兴起,金融领域的变革愈演愈烈。摆脱对国外技术和产品的过度依赖,构建行业网络安全环境,增强我国行业信息系统的安全可信度,显得尤为必要和紧迫。密码算法是保障信息安全的核心技术,尤其是银行业最关键的核心领域,长期以来一直采用3DES、SHA-1、RSA等国际通行的密码算法体系及相关标准。2010年底,国家密码管理局公布了我国自主研发的“椭圆曲线公钥密码算法”(SM2算法)。为确保密码在重要经济系统中的应用安全,国家密码管理局于2011年发布《关于做好公钥密码算法升级工作的通知》,明确要求“自2011年3月1日起,公钥密码基础设施电子认证系统和密钥管理系统应使用国密算法。自2011年7月1日起,已投入运行并采用公钥密码体制的信息系统,应当采用SM2算法。”2012年以来,国家密码管理局采用了SM2/SM3/SM4等密码算法标准,并陆续公布了其应用规范。其中“SM”代表“商业机密”,即用于商业目的的不涉及国家机密的密码技术。其中,以下公钥算法值得关注:SM2:一种基于椭圆曲线密码学(ECC)的公钥密码算法标准,提供数字签名、密钥交换、公钥加密,用于替代RSA/ECDSA/ECDH等。国际算法SM3:消息摘要算法,哈希结果为256位,用于替代MD5/SHA1/SHA256等国际算法SM4:对称加密算法,密钥长度和数据包长度均为128位,主要用于无线局域网标准,用于替代DES/AES等算法国密证书:这里的国密证书是指使用国密算法(SM2-with-SM3)的标准X509格式证书。证书使用SM3作为哈希算法,SM2作为数字签名算法国密SSL:采用国密算法,符合国密标准的安全传输协议,是SSL/TLS协议的国密版本。SM2进阶Linux内核之路目前,由于无线局域网标准的广泛使用,Linux内核已经很好地支持SM3和SM4算法。但是SM2算法和国密证书长期得不到支持,无法在内核中建立基于国密的全栈可信和完整性验证。因此,在内核中支持该系统已成为当务之急。整个计划是:在内核中支持SM2算法和国密证书,内部业务先申请后,最终推广到社区。整个过程下来,出现了很多问题,我有权记录下来。第一次有了计划,下一步就是考虑如何实施。对于任何密码算法,它首先会考虑是否可以从openssl移植过来。好在openssl对SM2/3/4的支持很好,椭圆曲线算法的实现也经过测试成熟,最新版本也全面支持国密证书。不幸的是,openssl的各个模块是高度耦合的。实现SM2和国密证书,需要移植openssl架构和基础代码,包括BIGNUM、ECC、X509等,这个工作量无疑是巨大的。即使实现了,这种方式也很难被社区所接受。经过深思熟虑,权衡利弊,果断放弃了这条“捷径”。第二轮发现了一个惊人的事实:内核中已经有了椭圆算法(crypto/ecc.c)的基本实现,为什么不尝试基于这个算法来做呢?于是开始参考SM2规范编码,结果有点遗憾。这个椭圆算法在SM2上居然失败了,连最基本的点积结果都错了!纳尼?剧本不应该是这样的。于是发邮件咨询了算法的资深开发者,很快得到了如下回复(感叹世界上还是有很多好心人):Shamir的trickalgo大概是generic,但是ecc_point_double_jacobian()就是曲线特定。选择的算法是我(和以前的编码器)使用的拟合曲线。如果要使用它们,您需要仔细检查它们的属性。使用过的算法的一些变体可能适合其他曲线,在参考论文中(在评论中)。总结一下原因:这个算法是一个高度优化的算法,已经精确适配NIST和ECRDSA椭圆曲线参数,但不一定适合国产SM2曲线参数。看来这条路走不通了……。哭了,别跟我说话。...擦干眼泪,看成败,豪迈一生,却又重头再来...经过第三轮反复探索,发现内核中的RSA算法是基于一个mpi(高精度整数)库,这个库来自libgcrypt(这是知名隐私保护软件GnuPG的底层算法实现)。内核中已经实现了一个早期版本的mpi,它是为实现RSA而引入的。现在libgcrypt已经有了完整的椭圆曲线基础算法,于是抱着试一试的心态测试了基于libgcrypt的SM2算法曲线。上帝保佑,这次惊喜没有变成震惊,实验结果与SM2规范一致。libgcrypt第四轮中的ECC算法是一种低耦合的通用算法。于是我想出了一个主意,你可以先在libgcrypt中尝试实现SM2,小试之后把这一套东西全部移植到内核中,进一步向社区推广。看来这也是一种能够被社区接受的方式。有了计划之后,索性摆出一个舒服的姿势,双手庄严地放在键盘上,让思绪随着手指自然流淌,接下来的开发调试就会比较顺利,很快就会有四种公钥算法。套件:加密、解密、签名、签名验证。一口气把这些实现提交给了libgcrypt社区。经过两轮评审和修改,SM2算法最终作为ECC的子算法被社区接受。在此,感谢libgcrypt的维护者之一NIIBEYutaka,他的耐心和友善,对中国传统文化的理解也深有体会。整体过程还是比较顺利的,就不提了。附上相关投稿:趁热打铁,因为内核中的lib/mpi库是旧版本,服务于RSA。与libgcrypt中的mpi相比,是一个阉割版,缺少的功能需要移植和ECC算法,这在技术上难度不大,但也是一个细活,工作量不小。在实践中,将SM2实现过程中缺失的东西全部移植过来,很快就实现了相应的SM2算法和国密证书。经过多轮打磨和全面测试,首批补丁即将面世:https://lkml.org/lkml/2020/2/16/43一次又一次,三和筋疲力尽,事情的进展再次遇到阻碍。Linux内核无法与专用密码库相提并论。社区对这种不太知名的算法并没有表现出太大的兴趣,甚至很少有人对此感兴趣。最后因为没有实际应用场景而被否决。当然,事情不能就这样结束。考虑到代码量大,维护人员审查意愿低,果断砍掉了SM2的加解密和签名,只保留了支持国密证书必要的签名验证功能。后来,一个接一个地做了。进行了一些小修,同时针对IMA的上游增强了国密算法,实现了IMA场景下国密功能的实际使用。同时,随着相关开发者和维护者不断的磨练chanhardlanbubbleda,新的patch也不断的发出,最终甚至摸清了maintainer习惯性的回复时间和patch整合的规律。慢慢推进SM2进入社区的步伐。这期间,没有波澜壮阔的故事,没有血腥的情节,balabalabala...,省略while(1){...}循环。七年过半的中秋节,一晃就是半年多的时间。SM2已经不是最熟悉的宝贝了,补丁不知不觉已经更新到v7版本了。中秋月圆之夜,总有大事要发生。是夜,一位天下英雄,头戴锅盖,腰缠海带,脚踏七彩祥云,飞了过来。SM2终于拿到了至尊宝。言归正传,这个版本的补丁终于被社区接受,已经合并到Linux主线的5.10-rc1中:https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/log/?qt=author&q=田家+张不出意外的话会在5.10内核版本正式发布。libgcrypt完全支持国密算法,有幸在某种机缘巧合下在libgcrypt中实现了SM4。作为国密发展进程的附属产品,目前libgcrypt已经全面支持国密算法SM2/3/4,这些实现将在下一个版本1.9.0正式发布。其中SM3是相关同事在2017年开发的,ima-evm-utils支持SM2-with-SM3国密签名内核已经支持SM2和国密证书。作为IMA完整性签名的用户模式工具,ima-evm-utils不能不支持国家机密。附加相关提交:https://sourceforge.net/p/linux-ima/ima-evm-utils/ci/ceecb28d3b5267c7d32c6e9401923c94f5786cfb/log/?path=KNOWNISSUES当前SM2仍有一些问题需要注意:SM2X509证书没有为SM2公钥算法定义独立的OID标识符。当前,默认识别标识符OID_id_ecPublicKey。SM2规范没有为推荐的椭圆曲线参数定义OID标识,这也导致SM2算法只有一个默认的椭圆曲线参数。签名时,除了计算消息本身的SM3。同时,SM2的椭圆曲线参数和公钥必须参与SM3的计算。SM2私钥签名是对最终的哈希结果进行签名。这个规范定义有点不同,这是与国际通用算法的重大区别。:一般情况下,X509证书解析和算法是作为独立的模块实现的。正是因为SM2的这种规范,才会导致实现上的强耦合:X509证书验证需要计算证书中tbs的SM3hash。这个hash还需要椭圆曲线参数和公钥数据,这些数据就是一个完整的SM2验证。签名过程中的临时数据,目前内核并没有提供这样的回调机制(当然这是SM2的特例),将X509证书解析和SM2算法强绑定在一起,无法解耦。这也导致该功能的应用受到一些限制。SM2只能支持内置编译(Y),不支持编译成模块(M)。让X509在编译的时候知道支持SM2,这样就可以正常验证国密证书了。从实现的角度来看,也有一些动态加载SM2模块获取函数指针的方法,相对于框架层的支持来说不是很友好。IMA签名计算文件哈希时,内核直接计算文件哈希,对于是否使用SM2签名没有做特殊处理(指上图中增加的Za值)。当前内核支持IMA国密签名校验,也支持ima-evm-utils的国密sm2+sm3签名(依赖最新的openssl)。目前,该块直接计算文件哈希,不添加Za值,这是目前最好的解决方案。需要注意的是,Za是在国密签名和签名验证过程中需要的,只是在签名验证过程中需要,但国密过程与目前的主流算法相悖。如果要支持的话,内核和ima-evm-utilstools需要做很大的修改,而且内核涉及架构修改,社区也不愿意接受,所以目前sm2的IMA签名+sm3以主流方式被支持。总而言之,概括起来就是两点:支持国密证书验证,SM2要么不编译,要么必须内置,不支持编译成模块。当然,SM2作为一种非对称算法,只是根据国家机密对hash或者IMA验证进行签名,没有这个限制。IMA签名工具ima-evm-utils和内核计算文件SM3哈希使用的国密算法没有加Za,与规范略有不同。
