1,boringssl添加新代码,编译。
设置编译环境setenv.bat
编译( net 依赖 crypto,boringssl)
gn gen --ide=vs2017 -sln=custume --filters=//net/*;//third_party/boringssl/*;//crypto/* out/vsproject (gn args out/Default) 生成了 build.ninja文件。类似makefile。
ninja -C out/vsproject boringssl (-C 选项告诉 ninja ,进入 out/Default 目录来编译。所以,它等同于:cd out/Default ninja)(net是模块名字,相当于target name,build.gn中指定)
如果同步到vs,用新的vxproj文件。
gn 用到的项目文件 .gn 、 .gni 和 DEPS ,它们指导了如何生成 ninja 构建文件。
如果把 gn 看成一个编译系统, .gn 就是源文件, .gni 就是头文件。我们姑且这么理解就好了(其实 gni 里做的事情, gn 都可以做)。DEPS 主要用来设定包含路径。
添加sm3 杂凑算法(vs SHA-256):
CHECK(MD5_Init(ctx->md_data));
}
static void md5_update(EVP_MD_CTX *ctx, const void *data, size_t count) {
CHECK(MD5_Update(ctx->md_data, data, count));
static void md5_final(EVP_MD_CTX *ctx, uint8_t *out) {
CHECK(MD5_Final(out, ctx->md_data));
DEFINE_METHOD_FUNCTION(EVP_MD, EVP_md5) {
out->type = NID_md5;
out->md_size = MD5_DIGEST_LENGTH;
out->flags = 0;
out->init = md5_init;
out->update = md5_update;
out->final = md5_final;
out->block_size = 64;
out->ctx_size = sizeof(MD5_CTX);
注意EVP_MD 结构体不一样,对应的位置要改变!!! 比如
boringssl:
EVP define method
需要对比
添加新算法:
The files nid.h, obj_mac.num, and obj_dat.h are generated from objects.txt and
obj_mac.num. To regenerate them, run:
go run objects.go
objects.txt contains the list of all built-in OIDs. It is processed by
objects.go to output obj_mac.num, obj_dat.h, and nid.h.
obj_mac.num is the list of NID values for each OID. This is an input/output
file so NID values are stable across regenerations.
nid.h is the header which defines macros for all the built-in OIDs in C.
obj_dat.h contains the ASN1_OBJECTs corresponding to built-in OIDs themselves
along with lookup tables for search by short name, OID, etc.
crypto/objects 目录下面维护整个OpenSSL模块化的重要的程序,下面逐个做出介绍。
objects.txt syntax
------------------
To cover all the naming hacks that were previously in objects.h needed some
kind of hacks in objects.txt.
The basic syntax for adding an object is as follows:
1 2 3 4 : shortName : Long Name
If Long Name contains only word characters and hyphen-minus
(0x2D) or full stop (0x2E) then Long Name is used as basis
for the base name in C. Otherwise, the shortName is used.
The base name (let's call it 'base') will then be used to
create the C macros SN_base, LN_base, NID_base and OBJ_base.
Note that if the base name contains spaces, dashes or periods,
those will be converted to underscore.
Then there are some extra commands:
!Alias foo 1 2 3 4
This just makes a name foo for an OID. The C macro
OBJ_foo will be created as a result.
!Cname foo
This makes sure that the name foo will be used as base name
in C.
!module foo
!global
The !module command was meant to define a kind of modularity.
What it does is to make sure the module name is prepended
to the base name. !global turns this off. This construction
is not recursive.
Lines starting with # are treated as comments, as well as any line starting
with ! and not matching the commands above.
sm4 oid:
!Cname pbe-WithSM3AndSMS4-CBC
pkcs12-pbeids 100 : PBE-SM3-SMS4 : pbeWithSM3AndSMS4-CBC
sm-scheme 104 1 : SMS4-ECB : sms4-ecb
sm-scheme 104 2 : SMS4-CBC : sms4-cbc
!Cname sms4-ofb128
sm-scheme 104 3 : SMS4-OFB : sms4-ofb
!Cname sms4-cfb128
sm-scheme 104 4 : SMS4-CFB : sms4-cfb
sm-scheme 104 5 : SMS4-CFB1 : sms4-cfb1
sm-scheme 104 6 : SMS4-CFB8 : sms4-cfb8
sm-scheme 104 7 : SMS4-CTR : sms4-ctr
sm-scheme 104 8 : SMS4-GCM : sms4-gcm
sm-scheme 104 9 : SMS4-CCM : sms4-ccm
sm-scheme 104 10 : SMS4-XTS : sms4-xts
sm-scheme 104 11 : SMS4-WRAP : sms4-wrap
sm-scheme 104 12 : SMS4-WRAP-PAD : sms4-wrap-pad
sm-scheme 104 100 : SMS4-OCB : sms4-ocb
1,在ciphter_extra.c 加入:
const EVP_CIPHER *EVP_get_cipherbynid(int nid) {
switch (nid) {
case NID_rc2_cbc:
return EVP_rc2_cbc();
default:
return NULL;
const EVP_CIPHER *EVP_get_cipherbyname(const char *name) {
if (OPENSSL_strcasecmp(name, "rc4") == 0) {
return EVP_rc4();
2,在src\crypto\fipsmodule\cipher 参考 e_aes.c 添加对外接口
3,注意 evp_cipher_st,evp_cipher_ctx_st 两者定义区别
4,evp_lib.c 在cipher.c (src\crypto\fipsmodule\cipher),evp.h -> cipher.h 实现。补充一些类似:EVP_CIPHER_CTX_get_cipher_data
5,EVP_CIPHER_do_all_sorted evp_do_all.c中排序。
生成oid后,加入evp。
digest_extra.c
#ifndef OPENSSL_NO_SM3
{NID_sm3, EVP_sm3, SN_sm3, LN_sm3},
#endif
// 1L, 2L, 156L, 10197L, 1L, 401L
{ {0x2a, 0x81, 0x1c, 0xcf, 0x55, 0x01, 0x83, 0x11}, 8, NID_sm3 }, //二进制从 obj_dat.h中搜sm3得到。
sm3测试

View Code
证书支持:
net::SSLPlatformKeyNSS::Sign in ssl_platform_key_nss.cc (E:\dev\cef-chromium\chromium\src\net\ssl) : case NID_sha256:
net::SSLPlatformKeyCAPI::Sign in ssl_platform_key_win.cc (E:\dev\cef-chromium\chromium\src\net\ssl) : case NID_sha256:
net::SSLPlatformKeyCNG::Sign in ssl_platform_key_win.cc (E:\dev\cef-chromium\chromium\src\net\ssl) : case NID_sha256:
不支持下面:
EVP_tls_cbc_record_digest_supported in tls_cbc.c (src\crypto\cipher_extra) : case NID_sha256:
EVP_tls_cbc_digest_record in tls_cbc.c (src\crypto\cipher_extra) : case NID_sha256:
ssl_cipher.cc ssl_ciph.c 放着算法套件
SM4:
证书里面用pkcs8.c (src\crypto\pkcs8) 参考rc4
p5_pbev2.c (src\crypto\pkcs8) line 94 : &EVP_rc2_cbc},
gmssl
2,ssl的引用:
E:\dev\cef-chromium\chromium\src\: net/socket/ssl_client_socket_impl
net 模块中:
build.gn
DEPS
密钥交换算法,证书验证算法
sm2的配置,脚本定义
sm-scheme 501 : SM2Sign-with-SM3 : sm2sign-with-sm3
sm-scheme 502 : SM2Sign-with-SHA1 : sm2sign-with-sha1
sm-scheme 503 : SM2Sign-with-SHA256 : sm2sign-with-sha256
sm-scheme 504 : SM2Sign-with-SHA511 : sm2sign-with-sha512
sm-scheme 505 : SM2Sign-with-SHA224 : sm2sign-with-sha224
sm-scheme 506 : SM2Sign-with-SHA384 : sm2sign-with-sha384
sm-scheme 507 : SM2Sign-with-RMD160 : sm2sign-with-rmd160
sm-scheme 520 : SM2Sign-with-Whirlpool : sm2sign-with-whirlpool
sm-scheme 521 : SM2Sign-with-Blake2b512 : sm2sign-with-blake2b512
sm-scheme 522 : SM2Sign-with-Blake2s256 : sm2sign-with-blake2s256
添加sm2算法(SM2椭圆曲线公钥密码算法(vs ECDSA、ECDH)):
evp_ctx.cc (third_party/boringssl/src/crypto/fipsmodule/evp_ctx.cc
ec.c
nid.h
ojb_dat.h
evp.h
添加EVP_PKEY_
添加 ec_method:
tassl中:
ec_lib.c 对应 ec.c
mont_data 搜索,与加入sm2有关。
mont_data对应 order_mont in boringssl
密钥套件添加
注意:
出错转换:
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_TYPE); 对应到 ECerr(EC_F_PKEY_EC_CTRL, EC_R_INVALID_DIGEST_TYPE);
<code>EVP_PKEY_HMAC</code> --》 the <code>HMAC_*</code>
key exchange是向量的问题, 少了3个长度.
多看几遍标准文档,查看向量的概念。
1. 使用签名证书计算z, id使用默认的\"1234567812345678\", 16字节;
2. 计算签名
hash = sm3(z + 32字节clientrandom + 32字节serverrandom + 加密证书i2d_x509序列化的内容)
sig = sm2sign(签名证书, hash)
实际过程是调用EVP_DigestSignXXX这个接口的
是签名证书 + 证书链 + 加密证书,还是签名证书 + 加密证书 + 证书链?在实现中发现TASSL采用的是前者,而沃通测试网站采用后者。
----------------------------
握手添加:
处理serverhello
test:
ssl3_get_record:SM1_1_VERSION
gclient是谷歌开发的一套跨平台git仓库管理工具,用来将多个git仓库组成一个solution进行管理。总体上,其核心功能是根据一个Solution的DEPS文件所定义的规则将多个git仓库拉取到指定目录。例如,chromium就是由80多个独立仓库组成。
hooks: 当gclient拉完代码后执行的额外脚本;
solution: 一个包含DEPS文件的仓库,可以认为是一个完整的项目;
DEPS: 一个特殊的文件,规定了项目依赖关系;
.gclient:一个特殊文件,规定了要拉取的solution,可由<code>gclient config</code>命令创建出来;
include_rules:指定当前目录下哪些目录/文件可以被其他代码include包含,哪些不可以被include。
帮助命令:
该命令会生成<code>.gclient</code>文件,用于初始化要拉取的solution,其内容记录了solution仓库的地址以及要保存的位置。
我们在拉取chromium代码时第一步其实也是生成了<code>.gclient</code>文件,内容如下:
以下是可以配置的字段:
name : checkout出源码的名字
url : 源码所在的目录,gclient希望checkout出的源码中包括一个DEPS的文件,这个文件包含了必须checkout到工作目录的源码的信息;
deps_file 这是一个文件名(不包括路径),指在工程目录中包含依赖列表的文件,该项为可选,默认值为"DEPS"
custom_deps 这是一个可选的字典对象,会覆盖工程的"DEPS"文件定义的条目。一般它用作本地目录中,那些不用checkout的代码;
target_os : 这个可选的条目可以指出特殊的平台,根据平台来checkout出不同代码
该命令用于同步solution的各个仓库,它有一些参数:
<code>-f</code>、<code>--force</code>:强制更新未更改的模块;
<code>--with_branch_heads</code>: 除了clone默认refspecs外,还会clone "branch_heads" refspecs;
<code>--with_tags</code>: 除了默认的refspec之外,还可以clone git tags;
<code>--no-history</code>: 不拉取git提交历史信息;
<code>--revision <version></code>: 将代码切换到 version 版本 ;
<code>--nohooks</code>:拉取代码之后不执行hooks。
拉取代码主要是根据<code>DEPS</code>文件来进行,它里面的内容包括:
<code>deps</code>: 要获取的子依赖项:
<code>vars</code>:定义字符串变量,一般用于替代公共的字符串,然后通过<code>Var</code>来获取实际的值:
<code>Hooks</code>:DEPS包含可选的内容 hooks,也有重要的作用,它表示在sync, update或者recert后,执行一个hook操作,也即执行对应的脚本;
<code>deps_os</code>:根据不同的平台定义不同的依赖工程,可选的包括:
执行hooks。当你拉取代码时使用了<code>--nohooks</code>参数时,就可以使用该命令来手动执行hooks。
在每个仓库中都执行一条git 命令
相当于每个仓库都执行了<code>git fetch</code>操作。
相当于每个仓库都执行<code>git diff</code> 操作。
相当于每个仓库都执行<code>git status</code> 操作。
更多指令可以使用<code>gclient --help</code>查看。
使用gclient拉取代码的时,主要使用以下命令:
3. gn入门
Chromium是用gn和ninja进行编译的,即gn把.gn文件转换成.ninja文件,然后ninja根据.ninja文件将源码生成目标程序。gn和ninja的关系就与cmake和make的关系差不多。
在我们自己的项目中,也可以使用gn来进行编译。
在windows上总是会遇到各种各样的问题,还是直接下载二进制程序省心:
然后设置环境变量,以便在命令行中直接使用。
这里写个hello_word来演示下gn的基本使用。
首先,写一个hello_word.cc源码文件:
然后在同一目录下创建BUILD.gn文件:
同时,gn还需要在项目根目录有一个.gn文件用于指定编译工具链。这里我们直接拷贝gn官方的例子的配置,完整工程:hello_world.zip
之后就可以直接执行编译:
这样就会在out/Default目录生成可执行文件hello_world.exe。
这样一个简单的示例就完成了。
在自己的项目中使用gn,必须遵循以下要求:
在根目录创建.gn文件,该文件用于指定BUILDCONFIG.gn文件的位置;
在BUILDCONFIG.gn中指定编译时使用的编译工具链;
在独立的gn文件中定义编译使用的工具链;
在项目根目录下创建BUILD.gn文件,指定编译的目标。