rec_layer_s3.c 收到alert 1530: else if (alert_level == SSL3_AL_FATAL || is_tls13) { char tmp[16]; s->rwstate = SSL_NOTHING; s->s3->fatal_alert = alert_descr; SSLfatal(s, SSL_AD_NO_ALERT, SSL_F_SSL3_READ_BYTES, SSL_AD_REASON_OFFSET + alert_descr); BIO_snprintf(tmp, sizeof tmp, "%d", alert_descr); ERR_add_error_data(2, "SSL alert number ", tmp); s->shutdown |= SSL_RECEIVED_SHUTDOWN; SSL3_RECORD_set_read(rr); SSL_CTX_remove_session(s->session_ctx, s->session);
1,boringssl添加新代碼,編譯。
設置編譯環境setenv.bat
set DEPOT_TOOLS_WIN_TOOLCHAIN=0 set GYP_GENERATORS=msvs-ninja,ninja set GYP_MSVS_VERSION=2015 set GYP_DEFINES=component=component=shared_library branding=Chromium buildtype=Official ffmpeg_branding=Chrome proprietary_codecs=1 set GYP_DEFINES=target_arch=x64 set GN_ARGUMENTS=--ide=vs2017 --sln=cef --filters=//cef/* set CEF=E:\dev\cef-chromium\depot_tools set PATH=%CEF%\win_tools-2_7_6_bin\python\bin\Scripts;%CEF%\win_tools-2_7_6_bin\python\bin;%CEF%;%PATH%; cd E:\dev\cef-chromium\chromium\src e:
添加完文件后,編譯
在src目錄: Note: when rolling DEPS forward, remember to run 執行前:注意先執行環境 cd third_party/boringssl python src/util/generate_build_files.py gn (python版本非常重要,確認是用的google的環境:depot_tools\win_tools-2_7_6_bin\python\bin\python.exe。windows需要替換"\") 或者安裝perl,go:, use the roll_boringssl.py script. 生成文件在: BUILD.generated.gni BUILD.generated_tests.gni (文件名帶test時)
編譯( net 依賴 crypto,boringssl)
gn gen --ide=vs2017 -sln=custume --filters=//net/*;//third_party/boringssl/*;//crypto/* out/vsproject (gn args out/Default) 生成了 build.ninja文件。類似makefile。
https://blog.csdn.net/ai2000ai/article/details/80894644
添加sm3 雜湊算法(vs SHA-256):
porting函數對照: https://gitee.com/setoutsoft/boringssl-with-bazel/blob/master/PORTING.md
evp.h 對應到了-> digest.h ( EVP_MD_CTX_md )
md5的evp在digest.c
static void md5_init(EVP_MD_CTX *ctx) {
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中沒有了
struct evp_md_st { int type; int pkey_type; int md_size; unsigned long flags; int (*init) (EVP_MD_CTX *ctx); int (*update) (EVP_MD_CTX *ctx, const void *data, size_t count); int (*final) (EVP_MD_CTX *ctx, unsigned char *md); int (*copy) (EVP_MD_CTX *to, const EVP_MD_CTX *from); int (*cleanup) (EVP_MD_CTX *ctx); int block_size; int ctx_size; /* how big does the ctx->md_data need to be */ /* control function */ int (*md_ctrl) (EVP_MD_CTX *ctx, int cmd, int p1, void *p2); } /* EVP_MD */ ; struct evp_md_ctx_st { const EVP_MD *digest; ENGINE *engine; /* functional reference if 'digest' is * ENGINE-provided */ unsigned long flags; void *md_data; /* Public key context for sign/verify */ EVP_PKEY_CTX *pctx; /* Update function: usually copied from EVP_MD */ int (*update) (EVP_MD_CTX *ctx, const void *data, size_t count); } /* EVP_MD_CTX */ ;
boringssl:
EVP_MD:
struct env_md_st { // type contains a NID identifing the digest function. (For example, // NID_md5.) int type; // md_size contains the size, in bytes, of the resulting digest. unsigned md_size; // flags contains the OR of |EVP_MD_FLAG_*| values. uint32_t flags; // init initialises the state in |ctx->md_data|. void (*init)(EVP_MD_CTX *ctx); // update hashes |len| bytes of |data| into the state in |ctx->md_data|. void (*update)(EVP_MD_CTX *ctx, const void *data, size_t count); // final completes the hash and writes |md_size| bytes of digest to |out|. void (*final)(EVP_MD_CTX *ctx, uint8_t *out); // block_size contains the hash's native block size. unsigned block_size; // ctx_size contains the size, in bytes, of the state of the hash function. unsigned ctx_size; }; struct env_md_ctx_st { // digest is the underlying digest function, or NULL if not set. const EVP_MD *digest; // md_data points to a block of memory that contains the hash-specific // context. void *md_data; // pctx is an opaque (at this layer) pointer to additional context that // EVP_PKEY functions may store in this object. EVP_PKEY_CTX *pctx; // pctx_ops, if not NULL, points to a vtable that contains functions to // manipulate |pctx|. const struct evp_md_pctx_ops *pctx_ops; } /* EVP_MD_CTX */;
EVP define method
// DEFINE_METHOD_FUNCTION defines a function named |name| which returns a // method table of type const |type|*. In FIPS mode, to avoid rel.ro data, it // is split into a CRYPTO_once_t-guarded initializer in the module and // unhashed, non-module accessor functions to space reserved in the BSS. The // method table is initialized by a caller-supplied function which takes a // parameter named |out| of type |type|*. The caller should follow the macro // invocation with the body of this function: // // DEFINE_METHOD_FUNCTION(EVP_MD, EVP_md4) { // out->type = NID_md4; // out->md_size = MD4_DIGEST_LENGTH; // out->flags = 0; // out->init = md4_init; // out->update = md4_update; // out->final = md4_final; // out->block_size = 64; // out->ctx_size = sizeof(MD4_CTX); // } // // This mechanism does not use a static initializer because their execution // order is undefined. See FIPS.md for more details.
需要對比
boringssl:fipsmodule/digest/md32_common.h
openssl的md32_common.h
引用字段不一樣了。
添加新算法:
1,添加算法ID
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 按照一定的語法結構,定義了
SN_base, LN_base, NID_base,OBJ_base。
經過perl程序objects.pl通過命令perl objects.pl objects.txt obj_mac.num obj_mac.h 處理后,生成了obj_mac.num 和obj_mac.h兩個文件。 obj_mac.num 用來查閱 OBJ_base與NID_base之間的對應關系。 obj_mac.h 用來提供c語言類型SN_base, LN_base, NID_base,OBJ_base定義。 objects.h 同樣提供了c語言類型SN_base, LN_base, NID_base,OBJ_base定義,在obj_mac.h 更新之后,必須對對應的objects.h 中的內容作出同步,及保持與obj_mac.h的定義一至,同時objects.h中也聲明了一些對OBJ_name的操作函數。
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
1 2 3 4 : shortName : Long Name
!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.
sm3 oid: !Cname pbe-WithSM3AndSMS4-CBC pkcs12-pbeids 100 : PBE-SM3-SMS4 : pbeWithSM3AndSMS4-CBC sm2encrypt 2 1 : sm2encrypt-with-sm3 sm-scheme 401 : SM3 : sm3 sm-scheme 401 2 : HMAC-SM3 : hmac-sm3 sm-scheme 501 : SM2Sign-with-SM3 : sm2sign-with-sm3 cpk-map 3 : cpk-sm3-map ---------------------------------------------------------------------- sm-scheme 401 : SM3 : sm3 sm-scheme 501 : SM2-SM3 : sm3WithSM2Sign sm-scheme 504 : RSA-SM3 : sm3WithRSAEncryption
sm4 oid:
tassl:
# Definitions for SM4 cipher sm-scheme 104 1 : SM4-ECB : sm4-ecb sm-scheme 104 2 : SM4-CBC : sm4-cbc !Cname sm4-ofb128 sm-scheme 104 3 : SM4-OFB : sm4-ofb !Cname sm4-cfb128 sm-scheme 104 4 : SM4-CFB : sm4-cfb sm-scheme 104 5 : SM4-CFB1 : sm4-cfb1 sm-scheme 104 6 : SM4-CFB8 : sm4-cfb8 sm-scheme 104 7 : SM4-CTR : sm4-ctr
---------------------------------------------------------------------
gmssl:
!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
1,
nid_to_digest_mapping[] = { {NID_md4, EVP_md4, SN_md4, LN_md4}, {NID_md5, EVP_md5, SN_md5, LN_md5},
#ifndef OPENSSL_NO_SM3
{NID_sm3, EVP_sm3, SN_sm3, LN_sm3},
#endif
...... 2, static const struct { uint8_t oid[9]; uint8_t oid_len; int nid; } kMDOIDs[] = { // 1.2.840.113549.2.4 { {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x04}, 8, NID_md4 }, // 1.2.840.113549.2.5 { {0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05}, 8, NID_md5 },
#ifndef OPENSSL_NO_SM3
// 1L, 2L, 156L, 10197L, 1L, 401L
{ {0x2a, 0x81, 0x1c, 0xcf, 0x55, 0x01, 0x83, 0x11}, 8, NID_sm3 }, //二進制從 obj_dat.h中搜sm3得到。
#endif
sm3測試

#pragma comment(lib, "boringsll.dll.lib") #include <stdio.h> #include <openssl/evp.h> #include <openssl/sm3.h> static size_t hash[8] = { 0 }; void out_hex(size_t* list1) { size_t i = 0; for (i = 0; i < 8; i++) { printf("%08x ", list1[i]); } printf("\r\n"); } int main(int argc, char* argv[]) { EVP_MD_CTX mdctx; const EVP_MD* md; char mess1[] = "abc"; char mess2[] = "abc"; unsigned char md_value[EVP_MAX_MD_SIZE]; unsigned int md_len, i; //使EVP_Digest系列函數支持所有有效的信息摘要算法 OpenSSL_add_all_digests(); //根據輸入的信息摘要函數的名字得到相應的EVP_MD算法結構 md = EVP_get_digestbyname("sm3"); //md = EVP_sm3(); if (!md) { printf("Unknown message digest %s\n", "sm3"); exit(1); } //初始化信息摘要結構mdctx,這在調用EVP_DigestInit_ex函數的時候是必須的。 EVP_MD_CTX_init(&mdctx); //使用md的算法結構設置mdctx結構,impl為NULL,即使用缺省實現的算法(openssl本身提供的信息摘要算法) EVP_DigestInit_ex(&mdctx, md, NULL); //開始真正進行信息摘要運算,可以多次調用該函數,處理更多的數據,這里只調用了兩次 EVP_DigestUpdate(&mdctx, mess1, strlen(mess1)); //EVP_DigestUpdate(&mdctx, mess2, strlen(mess2)); //完成信息摘要計算過程,將完成的摘要信息存儲在md_value里面,長度信息存儲在md_len里面 EVP_DigestFinal_ex(&mdctx, md_value, &md_len); //使用該函數釋放mdctx占用的資源,如果使用_ex系列函數,這是必須調用的。 EVP_MD_CTX_cleanup(&mdctx); printf("Digest is: "); for (i = 0; i < md_len; i++) printf("%02x", md_value[i]); printf("\n"); //SM3("abc",3,hash); //out_hex(hash); system("pause"); }
證書支持:
pkey_ec_ctrl in p_ec.c (src\crypto\evp)
crypto::ToOpenSSLDigestType in signature_creator.cc
SSL_CIPHER_get_digest_nid in ssl_cipher.cc (src\ssl) : return NID_sha256;
SSL_CIPHER_get_prf_nid in ssl_cipher.cc (src\ssl) : return NID_sha256;
SSLCipherSuiteToStrings in ssl_cipher_suite_names.cc
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
算法套件 : gmtls.h 算法 : ssl_ciph.c -> ssl_cipher.cc boring: tassl: 搜索 OPENSSL_NO_CNSM s3_lib.c #ifndef OPENSSL_NO_CNSM /* Cipher E011 */ { 1, TLS1_TXT_ECDHE_WITH_SM4_SM3, NULL, TLS1_CK_ECDHE_WITH_SM4_SM3, SSL_kSM2DH, SSL_aSM2DSA, SSL_SM4, SSL_SM3, TLS1_VERSION, TLS1_2_VERSION, 0, 0, SSL_HIGH, SSL_HANDSHAKE_MAC_SM3 | TLS1_PRF_SM3, 128, 128, }, /* Cipher E013 */ { 1, TLS1_TXT_ECC_WITH_SM4_SM3, NULL, TLS1_CK_ECC_WITH_SM4_SM3, SSL_kECC, SSL_aSM2DSA, SSL_SM4, SSL_SM3, TLS1_VERSION, TLS1_2_VERSION, 0, 0, SSL_HIGH, SSL_HANDSHAKE_MAC_SM3 | TLS1_PRF_SM3, 128, 128, }, #endif
2,ssl的引用:
E:\dev\cef-chromium\chromium\src\: net/socket/ssl_client_socket_impl
#include "third_party/boringssl/src/include/openssl/bio.h" #include "third_party/boringssl/src/include/openssl/bytestring.h" #include "third_party/boringssl/src/include/openssl/err.h" #include "third_party/boringssl/src/include/openssl/evp.h" #include "third_party/boringssl/src/include/openssl/mem.h" #include "third_party/boringssl/src/include/openssl/ssl.h"
net 模塊中:
build.gn
指定了依賴包
public_deps = [ ":net_nqe_proto", ":net_quic_proto", ":traffic_annotation", "//crypto", "//crypto:platform", "//third_party/boringssl", ]
DEPS
指定了頭文件 include_rules = [ "+crypto", "+gin", "+jni", "+mojo/public", "+third_party/apple_apsl", "+third_party/boringssl/src/include", "+third_party/nss", "+third_party/protobuf/src/google/protobuf", "+third_party/zlib", "+v8", # Most of net should not depend on icu, and brotli to keep size down when # built as a library. "-base/i18n", "-third_party/brotli", "-third_party/icu", ]
從 chromium\src\third_party\perl\c\include\openssl\opensslv.h 可以看到當前boringssl基於的版本。
chromium\src\components\webcrypto 自動生成密鑰
src\third_party\boringssl\src\crypto\evp\evptest.cc
BORINGSSL_NO_STATIC_INITIALIZER BORINGSSL_CONFIDENTIAL OPENSSL_NO_ASM BORINGSSL_FIPS
OPENSSL_NO_GMTLS OPENSSL_NO_SM2
BORINGSSL_PREFIX
https://github.com/lijunjieone/boringssl
密鑰交換算法,證書驗證算法
# NIDs for cipher key exchange : KxRSA : kx-rsa : KxECDHE : kx-ecdhe : KxDHE : kx-dhe : KxECDHE-PSK : kx-ecdhe-psk : KxDHE-PSK : kx-dhe-psk : KxRSA_PSK : kx-rsa-psk : KxPSK : kx-psk : KxSRP : kx-srp : KxGOST : kx-gost : KxSM2 : kx-sm2 : KxSM2DHE : kx-sm2dhe : KxSM2-PSK : kx-sm2-psk : KxSM9 : kx-sm9 : KxSM9DHE : kx-sm9dhe # NIDs for cipher authentication : AuthRSA : auth-rsa : AuthECDSA : auth-ecdsa : AuthPSK : auth-psk : AuthDSS : auth-dss : AuthGOST01 : auth-gost01 : AuthGOST12 : auth-gost12 : AuthSRP : auth-srp : AuthNULL : auth-null : AuthSM2 : auth-sm2 : AuthSM9 : auth-sm9
sm2的配置,腳本定義
sm-scheme 301 : sm2p256v1 sm-scheme 301 1 : sm2sign sm-scheme 301 2 : sm2exchange sm-scheme 301 3 : sm2encrypt #sm-scheme 301 101 : wapip192v1 sm2encrypt 1 : sm2encrypt-recommendedParameters sm2encrypt 2 : sm2encrypt-specifiedParameters sm2encrypt 2 1 : sm2encrypt-with-sm3 sm2encrypt 2 2 : sm2encrypt-with-sha1 sm2encrypt 2 3 : sm2encrypt-with-sha224 sm2encrypt 2 4 : sm2encrypt-with-sha256 sm2encrypt 2 5 : sm2encrypt-with-sha384 sm2encrypt 2 6 : sm2encrypt-with-sha512 sm2encrypt 2 7 : sm2encrypt-with-rmd160 sm2encrypt 2 8 : sm2encrypt-with-whirlpool sm2encrypt 2 9 : sm2encrypt-with-blake2b512 sm2encrypt 2 10 : sm2encrypt-with-blake2s256 sm2encrypt 2 11 : sm2encrypt-with-md5
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
static const EVP_PKEY_METHOD *const evp_methods[] = { &rsa_pkey_meth, &ec_pkey_meth, &ed25519_pkey_meth, };
ec.c
nist_curves[] =
放着所有
nid.h
#define SN_sm2 "SM2" #define LN_sm2 "sm2" #define NID_sm2 962 #define OBJ_sm2 1L, 2L, 156L, 10197L, 1L, 301L
ojb_dat.h
/* NID_sm2 */ 0x2a, 0x81, 0x1c, 0xcf, 0x55, 0x01, 0x82, 0x2d, /* NID_sm3WithSM2Sign */ 0x2a, 0x81, 0x1c, 0xcf, 0x55, 0x01, 0x83, 0x75, {"SM2", "sm2", NID_sm2, 8, &kObjectData[6192], 0}, {"SM2-SM3", "sm3WithSM2Sign", NID_sm3WithSM2Sign, 8, &kObjectData[6208], 0}, 962 /* 1.2.156.10197.1.301 (OBJ_sm2) */,
evp.h
添加EVP_PKEY_
# define EVP_PKEY_SM2 NID_sm2
添加 ec_method:
tassl中:
ec_ameth.c const EVP_PKEY_ASN1_METHOD sm2_asn1_meth = { EVP_PKEY_SM2, EVP_PKEY_EC, ASN1_PKEY_ALIAS }; -------------------------- boringssl里, 在crypto/evp/p_rsa_asn1.c 有專門的實現 搜索“rsa_asn1_meth”找到加入點: evp.c 中有方法集成: evp_pkey_asn1_find static const EVP_PKEY_ASN1_METHOD *evp_pkey_asn1_find(int nid) { switch (nid) { case EVP_PKEY_RSA: return &rsa_asn1_meth; case EVP_PKEY_EC: return &ec_asn1_meth; case EVP_PKEY_DSA: return &dsa_asn1_meth; case EVP_PKEY_ED25519: return &ed25519_asn1_meth; default: return NULL; } } evp_asn1.c中加入 static const EVP_PKEY_ASN1_METHOD *const kASN1Methods[] = { &rsa_asn1_meth, &ec_asn1_meth, &dsa_asn1_meth, &ed25519_asn1_meth, }; evp/internal.h中加入: extern const EVP_PKEY_ASN1_METHOD sm2_asn1_meth;
這個方法繼承自ec_asn1_meth,所以拷貝一樣。
搜 “EVP_PKEY_ED25519” 對簽名算法的引用
ec_lib.c 對應 ec.c
mont_data 搜索,與加入sm2有關。
mont_data對應 order_mont in boringssl
密鑰套件添加
1,密鑰套件 ECC-SM3-SM4 sm2_sign ECDSA_verify ec_計算臨時公私鑰 ec 添加sm3摘要支持
tls1_setup_key_block 添加sm4對稱密碼支持
tls1_final_finish_mac 添加sm2 finish mac計算
t1_lib.c ec算法添加nid sm2
tls1_get_supported_groups 支持算法添加sm2調用。
tls1_check_group_id 返回tls支持list
添加簽名算法支持sm3 define 查找函數。
tls12_get_psigalgs
tls1.h 支持的算法定義
statem_lib.c 增加證書鏈支持
tls_process_cert_verify 增加證書鏈驗證。
tls_setup_handshake 握手支持
tls_construct_client_certificate 客戶端證書支持ecc,sm2dh
tls_client_key_exchange_post_work sm4做對稱密鑰
tls_construct_client_key_exchange 客戶端密鑰支持ECC
tls_process_key_exchange 處理ECC密鑰交換
key_exchange_expected 增加支持key定義 ECC
ssl_rsa.c 添加 ECC 公私鑰設置。
ssl_set_cert 設置使用sm2時的證書
ssl_locl.h 添加 sm3的rsa , ecc,rsa enc,handshake sm3,
ssl_lib.c 檢查私鑰
ssl_cert_type 證書類型有 ECC enc
ssl_ciph 添加支持sm3的類型
ssl_cert.c 添加sm2證書 安裝加載
s3_lib.c 添加ec_pkey_ctx
ssl_generate_pkey_group 添加獲取私鑰sm2 組
ssl_generate_pkey 獲取私鑰sm2
ssl3_choose_cipher 選擇算法ECC_WITH_SM4_SM3
s3_lib.c 算法套件 對應算法套件加入: ssl_cipher.cc internal.h添加對應宏,如SSL_kECC
p_lib.c 添加engine調用
pmeth_lib.c 初始化engine
PEM_read_bio_PrivateKey 讀取私鑰
check_pem 支持sm2
do_sigver_init in m_sigver.c 簽名驗證
methods.c: 套件的cn method
eng_pkey.c 產生主密鑰
注意:
EVP_MD雙方定義不同。取值要注意。 const EVP_MD *kdf_md; EC_PKEY_CTX;
出錯轉換:
OPENSSL_PUT_ERROR(EVP, EVP_R_INVALID_DIGEST_TYPE); 對應到 ECerr(EC_F_PKEY_EC_CTRL, EC_R_INVALID_DIGEST_TYPE);
EVP_PKEY_HMAC
--》 the HMAC_*
2. 計算簽名
hash = sm3(z + 32字節clientrandom + 32字節serverrandom + 加密證書i2d_x509序列化的內容)
sig = sm2sign(簽名證書, hash)
實際過程是調用EVP_DigestSignXXX這個接口的
ssl_lib.cc handshake.cc handshake_client.cc 1, ssl_run_handshake -> do_start_connect->ssl_write_client_hello->ssl_wirte_client_cipher_list ->ssl3_add_message(ssl3_both.cc) ssl_lib.c中定義msg_callback 可以打印log info_callback ----------------------------------- // Skip disabled ciphers if ((cipher->algorithm_mkey & mask_k) || (cipher->algorithm_auth & mask_a)) ------------------------------------ ssl_cipher.cc 支持算法列表 ssl_create_cipher_list SSL_CTX_set_strict_cipher_list ssl.h #define SSL3_VERSION 0x0300 #define TLS1_VERSION 0x0301 #define TLS1_1_VERSION 0x0302 #define TLS1_2_VERSION 0x0303 #define TLS1_3_VERSION 0x0304 SSL_CIPHER_get_min_version ------------------- 代碼修改: ssl_cipher.c bool ssl_create_cipher_list函數: ssl_cipher_apply_rule(TLS1_CK_ECC_WITH_SM4_SM3, SSL_kECC, SSL_aSM2DSA, ~0u, ~0u, 0, CIPHER_ADD, -1, false, &head, &tail); uint16_t SSL_CIPHER_get_min_version(const SSL_CIPHER *cipher) { if (cipher->algorithm_mkey == SSL_kGENERIC || cipher->algorithm_auth == SSL_aGENERIC) { return TLS1_3_VERSION; } #ifndef OPENSSL_ZHI_CUST if (cipher->id == TLS1_CK_ECC_WITH_SM4_SM3) { // Cipher suites before TLS 1.2 use the default PRF, while all those added // afterwards specify a particular hash. return SM1_1_VERSION; } #endif
版本:
ssl_protocol_version_from_wire
t1_lib.cc
處理serverhello
ssl_get_handshake_digest
搜索參考實現: SM1_1_VERSION
ssl_get_version_range一定要注意返回失敗。
NET:
GetNetSSLVersion
DefaultAlgorithmPreferences
test:
ssl目錄下有test:bssl_shim.cc
ssl3_get_record:SM1_1_VERSION
參考:
http://www.itkeyword.com/doc/724141406683124207/openssl
https://www.cnblogs.com/solobearchn/p/8614776.html OPENSSL EC解釋
https://blog.csdn.net/runshui27/article/details/105633459 tassl 調用
https://www.cnblogs.com/cnblogs-wangzhipeng/p/9933562.html 國密sm2算法調用測試
編譯項目
# Building BoringSSL ## Build Prerequisites * [CMake](https://cmake.org/download/) 2.8.11 or later is required. * Perl 5.6.1 or later is required. On Windows, [Active State Perl](http://www.activestate.com/activeperl/) has been reported to work, as has MSYS Perl. [Strawberry Perl](http://strawberryperl.com/) also works but it adds GCC to `PATH`, which can confuse some build tools when identifying the compiler (removing `C:\Strawberry\c\bin` from `PATH` should resolve any problems). If Perl is not found by CMake, it may be configured explicitly by setting `PERL_EXECUTABLE`. * On Windows you currently must use [Ninja](https://ninja-build.org/) to build; on other platforms, it is not required, but recommended, because it makes builds faster. * If you need to build Ninja from source, then a recent version of [Python](https://www.python.org/downloads/) is required (Python 2.7.5 works). * On Windows only, [Yasm](http://yasm.tortall.net/) is required. If not found by CMake, it may be configured explicitly by setting `CMAKE_ASM_NASM_COMPILER`. * A C compiler is required. On Windows, MSVC 14 (Visual Studio 2015) or later with Platform SDK 8.1 or later are supported. Recent versions of GCC (4.8+) and Clang should work on non-Windows platforms, and maybe on Windows too. To build the tests, you also need a C++ compiler with C++11 support. * [Go](https://golang.org/dl/) is required. If not found by CMake, the go executable may be configured explicitly by setting `GO_EXECUTABLE`. * To build the x86 and x86\_64 assembly, your assembler must support AVX2 instructions and MOVBE. If using GNU binutils, you must have 2.22 or later ## Building Using Ninja (note the 'N' is capitalized in the cmake invocation): mkdir build cd build cmake -GNinja .. ninja Using Make (does not work on Windows): mkdir build cd build cmake .. make You usually don't need to run `cmake` again after changing `CMakeLists.txt` files because the build scripts will detect changes to them and rebuild themselves automatically. Note that the default build flags in the top-level `CMakeLists.txt` are for debugging—optimisation isn't enabled. Pass `-DCMAKE_BUILD_TYPE=Release` to `cmake` to configure a release build. If you want to cross-compile then there is an example toolchain file for 32-bit Intel in `util/`. Wipe out the build directory, recreate it and run `cmake` like this: cmake -DCMAKE_TOOLCHAIN_FILE=../util/32-bit-toolchain.cmake -GNinja .. If you want to build as a shared library, pass `-DBUILD_SHARED_LIBS=1`. On Windows, where functions need to be tagged with `dllimport` when coming from a shared library, define `BORINGSSL_SHARED_LIBRARY` in any code which `#include`s the BoringSSL headers. In order to serve environments where code-size is important as well as those where performance is the overriding concern, `OPENSSL_SMALL` can be defined to remove some code that is especially large. See [CMake's documentation](https://cmake.org/cmake/help/v3.4/manual/cmake-variables.7.html) for other variables which may be used to configure the build.
整合項目
# Incorporating BoringSSL into a project **Note**: if your target project is not a Google project then first read the [main README](/README.md) about the purpose of BoringSSL. ## Bazel If you are using [Bazel](https://bazel.build) then you can incorporate BoringSSL as an external repository by using a commit from the `master-with-bazel` branch. That branch is maintained by a bot from `master` and includes the needed generated files and a top-level BUILD file. For example: git_repository( name = "boringssl", commit = "_some commit_", remote = "https://boringssl.googlesource.com/boringssl", ) You would still need to keep the referenced commit up to date if a specific commit is referred to. ## Directory layout Typically projects create a `third_party/boringssl` directory to put BoringSSL-specific files into. The source code of BoringSSL itself goes into `third_party/boringssl/src`, either by copying or as a [submodule](https://git-scm.com/docs/git-submodule). It's generally a mistake to put BoringSSL's source code into `third_party/boringssl` directly because pre-built files and custom build files need to go somewhere and merging these with the BoringSSL source code makes updating things more complex. ## Build support BoringSSL is designed to work with many different build systems. Currently, different projects use [GYP](https://gyp.gsrc.io/), [GN](https://chromium.googlesource.com/chromium/src/+/master/tools/gn/docs/quick_start.md), [Bazel](https://bazel.build/) and [Make](https://www.gnu.org/software/make/) to build BoringSSL, without too much pain. The development build system is CMake and the CMake build knows how to automatically generate the intermediate files that BoringSSL needs. However, outside of the CMake environment, these intermediates are generated once and checked into the incorporating project's source repository. This avoids incorporating projects needing to support Perl and Go in their build systems. The script [`util/generate_build_files.py`](/util/generate_build_files.py) expects to be run from the `third_party/boringssl` directory and to find the BoringSSL source code in `src/`. You should pass it a single argument: the name of the build system that you're using. If you don't use any of the supported build systems then you should augment `generate_build_files.py` with support for it. The script will pregenerate the intermediate files (see [BUILDING.md](/BUILDING.md) for details about which tools will need to be installed) and output helper files for that build system. It doesn't generate a complete build script, just file and test lists, which change often. For example, see the [file](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/boringssl/BUILD.generated.gni) and [test](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/boringssl/BUILD.generated_tests.gni) lists generated for GN in Chromium. Generally one checks in these generated files alongside the hand-written build files. Periodically an engineer updates the BoringSSL revision, regenerates these files and checks in the updated result. As an example, see how this is done [in Chromium](https://code.google.com/p/chromium/codesearch#chromium/src/third_party/boringssl/). ## Defines BoringSSL does not present a lot of configurability in order to reduce the number of configurations that need to be tested. But there are a couple of \#defines that you may wish to set: `OPENSSL_NO_ASM` prevents the use of assembly code (although it's up to you to ensure that the build system doesn't link it in if you wish to reduce binary size). This will have a significant performance impact but can be useful if you wish to use tools like [AddressSanitizer](http://clang.llvm.org/docs/AddressSanitizer.html) that interact poorly with assembly code. `OPENSSL_SMALL` removes some code that is especially large at some performance cost. ## Symbols You cannot link multiple versions of BoringSSL or OpenSSL into a single binary without dealing with symbol conflicts. If you are statically linking multiple versions together, there's not a lot that can be done because C doesn't have a module system. If you are using multiple versions in a single binary, in different shared objects, ensure you build BoringSSL with `-fvisibility=hidden` and do not export any of BoringSSL's symbols. This will prevent any collisions with other verisons that may be included in other shared objects. Note that this requires that all callers of BoringSSL APIs live in the same shared object as BoringSSL. If you require that BoringSSL APIs be used across shared object boundaries, continue to build with `-fvisibility=hidden` but define `BORINGSSL_SHARED_LIBRARY` in both BoringSSL and consumers. BoringSSL's own source files (but *not* consumers' source files) must also build with `BORINGSSL_IMPLEMENTATION` defined. This will export BoringSSL's public symbols in the resulting shared object while hiding private symbols. However note that, as with a static link, this precludes dynamically linking with another version of BoringSSL or OpenSSL.
1.gclient簡介
gclient是谷歌開發的一套跨平台git倉庫管理工具,用來將多個git倉庫組成一個solution進行管理。總體上,其核心功能是根據一個Solution的DEPS文件所定義的規則將多個git倉庫拉取到指定目錄。例如,chromium就是由80多個獨立倉庫組成。
2.相關概念
- hooks: 當gclient拉完代碼后執行的額外腳本;
- solution: 一個包含DEPS文件的倉庫,可以認為是一個完整的項目;
- DEPS: 一個特殊的文件,規定了項目依賴關系;
- .gclient:一個特殊文件,規定了要拉取的solution,可由
gclient config
命令創建出來; - include_rules:指定當前目錄下哪些目錄/文件可以被其他代碼include包含,哪些不可以被include。
幫助命令:
gclient --help
3.常用命令
3.1 gclient config
該命令會生成.gclient
文件,用於初始化要拉取的solution,其內容記錄了solution倉庫的地址以及要保存的位置。
我們在拉取chromium代碼時第一步其實也是生成了.gclient
文件,內容如下:
solutions = [
{
"url": "https://chromium.googlesource.com/chromium/src.git", # Solution倉庫地址 "managed": False, "name": "src", # 拉取代碼后存放的位置 "custom_deps": {}, # 自定義依賴的倉庫地址 "custom_vars": {}, }, ]
以下是可以配置的字段:
- name : checkout出源碼的名字
- url : 源碼所在的目錄,gclient希望checkout出的源碼中包括一個DEPS的文件,這個文件包含了必須checkout到工作目錄的源碼的信息;
- deps_file 這是一個文件名(不包括路徑),指在工程目錄中包含依賴列表的文件,該項為可選,默認值為"DEPS"
- custom_deps 這是一個可選的字典對象,會覆蓋工程的"DEPS"文件定義的條目。一般它用作本地目錄中,那些不用checkout的代碼;
- target_os : 這個可選的條目可以指出特殊的平台,根據平台來checkout出不同代碼
3.2 gclient sync
該命令用於同步solution的各個倉庫,它有一些參數:
-f
、--force
:強制更新未更改的模塊;--with_branch_heads
: 除了clone默認refspecs外,還會clone "branch_heads" refspecs;--with_tags
: 除了默認的refspec之外,還可以clone git tags;--no-history
: 不拉取git提交歷史信息;--revision <version>
: 將代碼切換到 version 版本 ;--nohooks
:拉取代碼之后不執行hooks。
拉取代碼主要是根據DEPS
文件來進行,它里面的內容包括:
deps
: 要獲取的子依賴項:
deps = {
"src/outside" : "http://outside-server/trunk@1234", }
vars
:定義字符串變量,一般用於替代公共的字符串,然后通過Var
來獲取實際的值:
vars = {
'chromium_git': 'https://chromium.googlesource.com' } deps = { 'src/chrome/browser/resources/media_router/extension/src': Var('chromium_git') + '/media_router.git' + '@' + '475baa8b2eb0a7a9dd1c96c9c7a6a8d9035cc8d7', 'src/buildtools': Var('chromium_git') + '/chromium/buildtools.git' + '@' + Var('buildtools_revision') }
Hooks
:DEPS包含可選的內容 hooks,也有重要的作用,它表示在sync, update或者recert后,執行一個hook操作,也即執行對應的腳本;
hooks = [
{
#config git log format 'name': 'git-log', 'pattern': '.', 'action': [ 'python', 'src/git-log/config_commit.py', ], }, ... ]
deps_os
:根據不同的平台定義不同的依賴工程,可選的包括:
DEPS_OS_CHOICES = {
"win32": "win``` "win": "win", "cygwin": "win", "darwin": "mac", "mac": "mac", "unix": "unix", "linux": "unix", "linux2": "unix", "linux3": "unix", "android": "android", } deps_os = { "win": { "src/chrome/tools/test/reference_build/chrome_win": "/trunk/deps/reference_builds/chrome_win@197743", ..... }, "ios": { "src/third_party/GTM": (Var("googlecode_url") % "google-toolbox-for-mac") + "/trunk@" + Var("gtm_revision"), .... }, ... }
3.3 gclient runhooks
執行hooks。當你拉取代碼時使用了--nohooks
參數時,就可以使用該命令來手動執行hooks。
3.4 gclient recurse
在每個倉庫中都執行一條git 命令
3.5 gclient fetch
相當於每個倉庫都執行了git fetch
操作。
3.6 gclient diff
相當於每個倉庫都執行git diff
操作。
3.7 gclient status
相當於每個倉庫都執行git status
操作。
更多指令可以使用gclient --help
查看。
4. 拉取代碼流程
使用gclient拉取代碼的時,主要使用以下命令:
3. gn入門
Chromium是用gn和ninja進行編譯的,即gn把.gn文件轉換成.ninja文件,然后ninja根據.ninja文件將源碼生成目標程序。gn和ninja的關系就與cmake和make的關系差不多。
1. 環境配置
在我們自己的項目中,也可以使用gn來進行編譯。
在windows上總是會遇到各種各樣的問題,還是直接下載二進制程序省心:
https://github.com/ninja-build/ninja/releases https://chrome-infra-packages.appspot.com/p/gn/gn
然后設置環境變量,以便在命令行中直接使用。
2. 示例
這里寫個hello_word來演示下gn的基本使用。
首先,寫一個hello_word.cc源碼文件:
#include <iostream> int main() { std::cout << "Hello world: gn build example" << std::endl; return 0; }
然后在同一目錄下創建BUILD.gn文件:
executable("hello_world") {
sources = [
"hello_world.cc",
]
}
同時,gn還需要在項目根目錄有一個.gn文件用於指定編譯工具鏈。這里我們直接拷貝gn官方的例子的配置,完整工程:hello_world.zip
之后就可以直接執行編譯:
gn gen out/Default
ninja -C out/Default
這樣就會在out/Default目錄生成可執行文件hello_world.exe。
這樣一個簡單的示例就完成了。
在自己的項目中使用gn,必須遵循以下要求:
- 在根目錄創建.gn文件,該文件用於指定BUILDCONFIG.gn文件的位置;
- 在BUILDCONFIG.gn中指定編譯時使用的編譯工具鏈;
- 在獨立的gn文件中定義編譯使用的工具鏈;
- 在項目根目錄下創建BUILD.gn文件,指定編譯的目標。
3. gn命令
gn gen out/dir [--args="..."]:創建新的編譯目錄,會自動創建args.gn文件作為編譯參數。
gn args --list out/dir:列出可選的編譯參數。
gn ls out/dir:列出所有的target;
gn ls out/dir "//:hello_word*":列出匹配的target;
gn desc out/dir "//:hello_word":查看指定target的描述信息,包括src源碼文件、依賴的lib、編譯選項等;
gn refs out/dir 文件:查看依賴該文件的target;
gn refs out/dir //:hello_word:查看依賴該target的target
。。。
注意//代表從項目根目錄開始。
4. BUILD.gn文件語法
gn語法很接近python,主要的官方文檔是以下兩篇:
https://chromium.googlesource.com/chromium/src/tools/gn/+/48062805e19b4697c5fbd926dc649c78b6aaa138/docs/language.md
https://gn.googlesource.com/gn/+/master/docs/reference.md
這里簡單介紹下一些關鍵用法:
4.1 新增編譯參數
declare_args() {
enable_test = true
}
這樣就新增了一個enable_test的gn編譯參數,默認值是true。在BUILD.gn文件中,你就可以根據這個編譯參數的值進行一些特殊化配置:
if(enable_test)
{
...
}
4.2 新增宏
defines = [ "AWESOME_FEATURE", "LOG_LEVEL=3" ]
這些宏可以直接在C++或C代碼中使用。
4.3 新增編譯單元
target就是一個最小的編譯單元,可以將它單獨傳遞給ninja進行編譯。
從google文檔上看有以下幾種target:
- action: Declare a target that runs a script a single time.(指定一段指定的腳本)
- action_foreach: Declare a target that runs a script over a set of files.(為一組輸入文件分別執行一次腳本)
- bundle_data: [iOS/macOS] Declare a target without output. (聲明一個無輸出文件的target)
- copy: Declare a target that copies files. (聲明一個只是拷貝文件的target)
- create_bundle: [iOS/macOS] Build an iOS or macOS bundle. (編譯MACOS/IOS包)
- executable: Declare an executable target. (生成可執行程序)
- generated_file: Declare a generated_file target.
- group: Declare a named group of targets. (執行一組target編譯)
- loadable_module: Declare a loadable module target. (創建運行時加載動態連接庫,和deps方式有一些區別)
- rust_library: Declare a Rust library target.
- shared_library: Declare a shared library target. (生成動態鏈接庫,.dll or .so)
- source_set: Declare a source set target. (生成靜態庫,比static_library要快)
- static_library: Declare a static library target. (生成靜態鏈接庫,.lib or .a)
- target: Declare an target with the given programmatic type.
因此,我們的hello示例其實也只是增加了一個executable target。
4.4 新增配置
使用config可以提供一個公共的配置對象,包括編譯flag、include、defines等,可被其他target包含。
config("myconfig") {
include_dirs = [ "include/common" ]
defines = [ "ENABLE_DOOM_MELON" ]
}
executable("mything") {
configs = [ ":myconfig" ]
}
4.5 新增模板
模板,顧名思義,可以用來定義可重用的代碼,比如添加新的target類型等。
通常可以將模板單獨定義成一個.gni文件,然后其他文件就可以通過import來引入實現共享。這部分就比較復雜,具體例子可參閱官方文檔。
4.6 新增依賴關系
平時我們在編譯的時候都會很小心地處理各種動態庫和靜態庫的鏈接引入,在gn中,我們需要使用deps來實現庫的依賴關系:
if (enable_nacl) {
deps += [ "//components/nacl/loader:nacl_loader_unittests" ]
if (is_linux) {
# TODO(dpranke): Figure out what platforms should actually have this.
deps += [ "//components/nacl/loader:nacl_helper" ]
if (enable_nacl_nonsfi) {
deps += [
"//components/nacl/loader:helper_nonsfi",
"//components/nacl/loader:nacl_helper_nonsfi_unittests",
]
}
}
}
5.通用toolchain配置
gn編譯的toolchain配置非常關鍵,決定了你編譯的方式和產物的用途,chromium自帶的toolchains也能實現跨平台,但是太過龐大,我們日常使用的話,可以使用:https://github.com/timniederhausen/gn-build
6.使用gn編譯mini_chromium庫
mini_chromium提供了一個mini版本的chromium base庫,里面提供很多有用的工具:日志庫、字符串處理、文件處理等,github地址:https://github.com/chromium/mini_chromium.git 。
默認它使用的是gyp編譯,但是其實它已經寫好了BUILD.gn文件,我們只需添加.gn文件指定編譯工具鏈即可,修改后的倉庫:https://github.com/243286065/mini_chromium.git。
最后是再windows上和ubuntu上測試通過。不過發現mini_chromium上的確實內容太少了,連timer和json庫都沒有。
Porting from OpenSSL to BoringSSL
BoringSSL is an OpenSSL derivative and is mostly source-compatible, for the subset of OpenSSL retained. Libraries ideally need little to no changes for BoringSSL support, provided they do not use removed APIs. In general, see if the library compiles and, on failure, consult the documentation in the header files and see if problematic features can be removed.
BoringSSL‘s OPENSSL_VERSION_NUMBER
matches the OpenSSL version it targets. Version checks for OpenSSL should ideally work as-is in BoringSSL. BoringSSL also defines upstream’s OPENSSL_NO_*
feature macros corresponding to removed features. If the preprocessor is needed, use these version checks or feature macros where possible, especially when patching third-party projects. Such patches are more generally useful to OpenSSL consumers and thus more appropriate to send upstream.
In some cases, BoringSSL-specific code may be necessary. Use the OPENSSL_IS_BORINGSSL
preprocessor macro in #ifdef
s. However, first contact the BoringSSL maintainers about the missing APIs. We will typically add compatibility functions for convenience. In particular, contact BoringSSL maintainers before working around missing OpenSSL 1.1.0 accessors. BoringSSL was originally derived from OpenSSL 1.0.2 but now targets OpenSSL 1.1.0. Some newer APIs may be missing but can be added on request. (Not all projects have been ported to OpenSSL 1.1.0, so BoringSSL also remains largely compatible with OpenSSL 1.0.2.)
The OPENSSL_IS_BORINGSSL
macro may also be used to distinguish OpenSSL from BoringSSL in configure scripts. Do not use the presence or absence of particular symbols to detect BoringSSL.
Note: BoringSSL does not have a stable API or ABI. It must be updated with its consumers. It is not suitable for, say, a system library in a traditional Linux distribution. For instance, Chromium statically links the specific revision of BoringSSL it was built against. Likewise, Android's system-internal copy of BoringSSL is not exposed by the NDK and must not be used by third-party applications.
Major API changes
Integer types
Some APIs have been converted to use size_t
for consistency and to avoid integer overflows at the API boundary. (Existing logic uses a mismash of int
, long
, and unsigned
.) For the most part, implicit casts mean that existing code continues to compile. In some cases, this may require BoringSSL-specific code, particularly to avoid compiler warnings.
Most notably, the STACK_OF(T)
types have all been converted to use size_t
instead of int
for indices and lengths.
Reference counts and opaque types
Some external consumers increment reference counts directly by calling CRYPTO_add
with the corresponding CRYPTO_LOCK_*
value. These APIs no longer exist in BoringSSL. Instead, code which increments reference counts should call the corresponding FOO_up_ref
function, such as EVP_PKEY_up_ref
.
BoringSSL also hides some structs which were previously exposed in OpenSSL 1.0.2, particularly in libssl. Use the relevant accessors instead.
Note that some of these APIs were added in OpenSSL 1.1.0, so projects which do not yet support 1.1.0 may need additional #ifdef
s. Projects supporting OpenSSL 1.1.0 should not require modification.
Error codes
OpenSSL's errors are extremely specific, leaking internals of the library, including even a function code for the function which emitted the error! As some logic in BoringSSL has been rewritten, code which conditions on the error may break (grep for ERR_GET_REASON
and ERR_GET_FUNC
). This danger also exists when upgrading OpenSSL versions.
Where possible, avoid conditioning on the exact error reason. Otherwise, a BoringSSL #ifdef
may be necessary. Exactly how best to resolve this issue is still being determined. It's possible some new APIs will be added in the future.
Function codes have been completely removed. Remove code which conditions on these as it will break with the slightest change in the library, OpenSSL or BoringSSL.
*_ctrl
functions
Some OpenSSL APIs are implemented with ioctl
-style functions such as SSL_ctrl
and EVP_PKEY_CTX_ctrl
, combined with convenience macros, such as
# define SSL_CTX_set_mode(ctx,op) \ SSL_CTX_ctrl((ctx),SSL_CTRL_MODE,(op),NULL)
In BoringSSL, these macros have been replaced with proper functions. The underlying _ctrl
functions have been removed.
For convenience, SSL_CTRL_*
values are retained as macros to doesnt_exist
so existing code which uses them (or the wrapper macros) in #ifdef
expressions will continue to function. However, the macros themselves will not work.
Switch any *_ctrl
callers to the macro/function versions. This works in both OpenSSL and BoringSSL. Note that BoringSSL's function versions will be type-checked and may require more care with types. See the end of this document for a table of functions to use.
HMAC EVP_PKEY
s
EVP_PKEY_HMAC
is removed. Use the HMAC_*
functions in hmac.h
instead. This is compatible with OpenSSL.
DSA EVP_PKEY
s
EVP_PKEY_DSA
is deprecated. It is currently still possible to parse DER into a DSA EVP_PKEY
, but signing or verifying with those objects will not work.
DES
The DES_cblock
type has been switched from an array to a struct to avoid the pitfalls around array types in C. Where features which require DES cannot be disabled, BoringSSL-specific codepaths may be necessary.
TLS renegotiation
OpenSSL enables TLS renegotiation by default and accepts renegotiation requests from the peer transparently. Renegotiation is an extremely problematic protocol feature, so BoringSSL rejects peer renegotiations by default.
To enable renegotiation, call SSL_set_renegotiate_mode
and set it to ssl_renegotiate_once
or ssl_renegotiate_freely
. Renegotiation is only supported as a client in TLS and the HelloRequest must be received at a quiet point in the application protocol. This is sufficient to support the common use of requesting a new client certificate between an HTTP request and response in (unpipelined) HTTP/1.1.
Things which do not work:
-
There is no support for renegotiation as a server. (Attempts by clients will result in a fatal alert so that ClientHello messages cannot be used to flood a server and escape higher-level limits.)
-
There is no support for renegotiation in DTLS.
-
There is no support for initiating renegotiation;
SSL_renegotiate
always fails andSSL_set_state
does nothing. -
Interleaving application data with the new handshake is forbidden.
-
If a HelloRequest is received while
SSL_write
has unsent application data, the renegotiation is rejected. -
Renegotiation does not participate in session resumption. The client will not offer a session on renegotiation or resume any session established by a renegotiation handshake.
-
The server may not change its certificate in the renegotiation. This mitigates the triple handshake attack. Any new stapled OCSP response and SCT list will be ignored. As no authentication state may change, BoringSSL will not re-verify the certificate on a renegotiation. Callbacks such as
SSL_CTX_set_custom_verify
will only run on the initial handshake.
Lowercase hexadecimal
BoringSSL's BN_bn2hex
function uses lowercase hexadecimal digits instead of uppercase. Some code may require changes to avoid being sensitive to this difference.
Legacy ASN.1 functions
OpenSSL's ASN.1 stack uses d2i
functions for parsing. They have the form:
RSA *d2i_RSAPrivateKey(RSA **out, const uint8_t **inp, long len);
In addition to returning the result, OpenSSL places it in *out
if out
is not NULL
. On input, if *out
is not NULL
, OpenSSL will usually (but not always) reuse that object rather than allocating a new one. In BoringSSL, these functions are compatibility wrappers over a newer ASN.1 stack. Even if *out
is not NULL
, these wrappers will always allocate a new object and free the previous one.
Ensure that callers do not rely on this object reuse behavior. It is recommended to avoid the out
parameter completely and always pass in NULL
. Note that less error-prone APIs are available for BoringSSL-specific code (see below).
Memory allocation
OpenSSL provides wrappers OPENSSL_malloc
and OPENSSL_free
over the standard malloc
and free
. Memory allocated by OpenSSL should be released with OPENSSL_free
, not the standard free
. However, by default, they are implemented directly using malloc
and free
, so code which mixes them up usually works.
In BoringSSL, these functions maintain additional book-keeping to zero memory on OPENSSL_free
, so any mixups must be fixed.
Optional BoringSSL-specific simplifications
BoringSSL makes some changes to OpenSSL which simplify the API but remain compatible with OpenSSL consumers. In general, consult the BoringSSL documentation for any functions in new BoringSSL-only code.
Return values
Most OpenSSL APIs return 1 on success and either 0 or -1 on failure. BoringSSL has narrowed most of these to 1 on success and 0 on failure. BoringSSL-specific code may take advantage of the less error-prone APIs and use !
to check for errors.
Initialization
OpenSSL has a number of different initialization functions for setting up error strings and loading algorithms, etc. All of these functions still exist in BoringSSL for convenience, but they do nothing and are not necessary.
The one exception is CRYPTO_library_init
. In BORINGSSL_NO_STATIC_INITIALIZER
builds, it must be called to query CPU capabilities before the rest of the library. In the default configuration, this is done with a static initializer and is also unnecessary.
Threading
OpenSSL provides a number of APIs to configure threading callbacks and set up locks. Without initializing these, the library is not thread-safe. Configuring these does nothing in BoringSSL. Instead, BoringSSL calls pthreads and the corresponding Windows APIs internally and is always thread-safe where the API guarantees it.
ASN.1
BoringSSL is in the process of deprecating OpenSSL's d2i
and i2d
in favor of new functions using the much less error-prone CBS
and CBB
types. BoringSSL-only code should use those functions where available.
Replacements for CTRL
values
When porting code which uses SSL_CTX_ctrl
or SSL_ctrl
, use the replacement functions below. If a function has both SSL_CTX
and SSL
variants, only the SSL_CTX
version is listed.
Note some values correspond to multiple functions depending on the larg
parameter.
CTRL value |
Replacement function(s) |
---|---|
DTLS_CTRL_GET_TIMEOUT |
DTLSv1_get_timeout |
DTLS_CTRL_HANDLE_TIMEOUT |
DTLSv1_handle_timeout |
SSL_CTRL_CHAIN |
SSL_CTX_set0_chain or SSL_CTX_set1_chain |
SSL_CTRL_CHAIN_CERT |
SSL_add0_chain_cert or SSL_add1_chain_cert |
SSL_CTRL_CLEAR_EXTRA_CHAIN_CERTS |
SSL_CTX_clear_extra_chain_certs |
SSL_CTRL_CLEAR_MODE |
SSL_CTX_clear_mode |
SSL_CTRL_CLEAR_OPTIONS |
SSL_CTX_clear_options |
SSL_CTRL_EXTRA_CHAIN_CERT |
SSL_CTX_add_extra_chain_cert |
SSL_CTRL_GET_CHAIN_CERTS |
SSL_CTX_get0_chain_certs |
SSL_CTRL_GET_CLIENT_CERT_TYPES |
SSL_get0_certificate_types |
SSL_CTRL_GET_EXTRA_CHAIN_CERTS |
SSL_CTX_get_extra_chain_certs or SSL_CTX_get_extra_chain_certs_only |
SSL_CTRL_GET_MAX_CERT_LIST |
SSL_CTX_get_max_cert_list |
SSL_CTRL_GET_NUM_RENEGOTIATIONS |
SSL_num_renegotiations |
SSL_CTRL_GET_READ_AHEAD |
SSL_CTX_get_read_ahead |
SSL_CTRL_GET_RI_SUPPORT |
SSL_get_secure_renegotiation_support |
SSL_CTRL_GET_SESSION_REUSED |
SSL_session_reused |
SSL_CTRL_GET_SESS_CACHE_MODE |
SSL_CTX_get_session_cache_mode |
SSL_CTRL_GET_SESS_CACHE_SIZE |
SSL_CTX_sess_get_cache_size |
SSL_CTRL_GET_TLSEXT_TICKET_KEYS |
SSL_CTX_get_tlsext_ticket_keys |
SSL_CTRL_GET_TOTAL_RENEGOTIATIONS |
SSL_total_renegotiations |
SSL_CTRL_MODE |
SSL_CTX_get_mode or SSL_CTX_set_mode |
SSL_CTRL_NEED_TMP_RSA |
SSL_CTX_need_tmp_RSA is equivalent, but do not use this function. (It is a no-op in BoringSSL.) |
SSL_CTRL_OPTIONS |
SSL_CTX_get_options or SSL_CTX_set_options |
SSL_CTRL_SESS_NUMBER |
SSL_CTX_sess_number |
SSL_CTRL_SET_CURVES |
SSL_CTX_set1_curves |
SSL_CTRL_SET_ECDH_AUTO |
SSL_CTX_set_ecdh_auto |
SSL_CTRL_SET_MAX_CERT_LIST |
SSL_CTX_set_max_cert_list |
SSL_CTRL_SET_MAX_SEND_FRAGMENT |
SSL_CTX_set_max_send_fragment |
SSL_CTRL_SET_MSG_CALLBACK |
SSL_set_msg_callback |
SSL_CTRL_SET_MSG_CALLBACK_ARG |
SSL_set_msg_callback_arg |
SSL_CTRL_SET_MTU |
SSL_set_mtu |
SSL_CTRL_SET_READ_AHEAD |
SSL_CTX_set_read_ahead |
SSL_CTRL_SET_SESS_CACHE_MODE |
SSL_CTX_set_session_cache_mode |
SSL_CTRL_SET_SESS_CACHE_SIZE |
SSL_CTX_sess_set_cache_size |
SSL_CTRL_SET_TLSEXT_HOSTNAME |
SSL_set_tlsext_host_name |
SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG |
SSL_CTX_set_tlsext_servername_arg |
SSL_CTRL_SET_TLSEXT_SERVERNAME_CB |
SSL_CTX_set_tlsext_servername_callback |
SSL_CTRL_SET_TLSEXT_TICKET_KEYS |
SSL_CTX_set_tlsext_ticket_keys |
SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB |
SSL_CTX_set_tlsext_ticket_key_cb |
SSL_CTRL_SET_TMP_DH |
SSL_CTX_set_tmp_dh |
SSL_CTRL_SET_TMP_DH_CB |
SSL_CTX_set_tmp_dh_callback |
SSL_CTRL_SET_TMP_ECDH |
SSL_CTX_set_tmp_ecdh |
SSL_CTRL_SET_TMP_ECDH_CB |
SSL_CTX_set_tmp_ecdh_callback |
SSL_CTRL_SET_TMP_RSA |
SSL_CTX_set_tmp_rsa is equivalent, but do not use this function. (It is a no-op in BoringSSL.) |
SSL_CTRL_SET_TMP_RSA_CB |
SSL_CTX_set_tmp_rsa_callback is equivalent, but do not use this function. (It is a no-op in BoringSSL.) |
Significant API additions
In some places, BoringSSL has added significant APIs. Use of these APIs goes beyound “porting” and means giving up on OpenSSL compatibility.
One example of this has already been mentioned: the CBS and CBB functions should be used whenever parsing or serialising data.
CRYPTO_BUFFER
With the standard OpenSSL APIs, when making many TLS connections, the certificate data for each connection is retained in memory in an expensive X509
structure. Additionally, common certificates often appear in the chains for multiple connections and are needlessly duplicated in memory.
A CRYPTO_BUFFER
is just an opaque byte string. A CRYPTO_BUFFER_POOL
is an intern table for these buffers, i.e. it ensures that only a single copy of any given byte string is kept for each pool.
The function TLS_with_buffers_method
returns an SSL_METHOD
that avoids creating X509
objects for certificates. Additionally, SSL_CTX_set0_buffer_pool
can be used to install a pool on an SSL_CTX
so that certificates can be deduplicated across connections and across SSL_CTX
s.
When using these functions, the application also needs to ensure that it doesn't call other functions that deal with X509
or X509_NAME
objects. For example, SSL_get_peer_certificate
or SSL_get_peer_cert_chain
. Doing so will trigger an assert in debug mode and will result in NULLs in release mode. Instead, call the buffer-based alternatives such as SSL_get0_peer_certificates
. (See ssl.h for functions taking or returning CRYPTO_BUFFER
.) The buffer-based alternative functions will work even when not using TLS_with_buffers_method
, thus application code can transition gradually.
In order to use buffers, the application code also needs to implement its own certificate verification using SSL_[CTX_]set_custom_verify
. Otherwise all connections will fail with a verification error. Auto-chaining is also disabled when using buffers.
Once those changes have been completed, the whole of the OpenSSL X.509 and ASN.1 code should be eliminated by the linker if BoringSSL is linked statically.
Asynchronous and opaque private keys
OpenSSL offers the ENGINE API for implementing opaque private keys (i.e. private keys where software only has oracle access because the secrets are held in special hardware or on another machine). While the ENGINE API has been mostly removed from BoringSSL, it is still possible to support opaque keys in this way. However, when using such keys with TLS and BoringSSL, you should strongly prefer using SSL_PRIVATE_KEY_METHOD
via SSL[_CTX]_set_private_key_method
. This allows a handshake to be suspended while the private operation is in progress. It also supports more forms of opaque key as it exposes higher-level information about the operation to be performed.
編譯器只有三種:微軟的msvc,GNU的gcc,蘋果的clang+llvm
各平台有自己的make(微軟的MS nmake、GNU的make),這個是依賴平台的,無法避開的最后編譯。
cmake可以跨平台生成各平台的make。但隨着源碼規模大,編譯速度需提升。產生ninja,gn。ninja相當於預編譯,查找好復雜的依賴。
用gn的工作方式:
1,gn生成各個平台的工程(xcode工程、vs工程)。用ide編輯修改源碼或者工程模塊后,同步回gn中。
或者2,vscode+gn
gn gen 后生成了build.njia
https://webencrypt.org/
http://www.voidcn.com/article/p-tdmxpevx-bqg.html