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。
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):
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");
}
View Code
证书支持:
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_*
key exchange是向量的问题, 少了3个长度.
多看几遍标准文档,查看向量的概念。
1. 使用签名证书计算z, id使用默认的\"1234567812345678\", 16字节;
2. 计算签名
hash = sm3(z + 32字节clientrandom + 32字节serverrandom + 加密证书i2d_x509序列化的内容)
sig = sm2sign(签名证书, hash)
实际过程是调用EVP_DigestSignXXX这个接口的
是签名证书 + 证书链 + 加密证书,还是签名证书 + 加密证书 + 证书链?在实现中发现TASSL采用的是前者,而沃通测试网站采用后者。
----------------------------
握手添加:
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
编译项目
# 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文件,指定编译的目标。