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檔案,指定編譯的目标。