前言
tls_construct_cert_verify是openSSL源码中的一个方法,用于进行TLS握手阶段的署名流程。
从概念上讲,数字署名的流程是如许的:
- 客户端根据一段公共消息天生消息摘要,一样平常是使用sha256算法。
- 客户端对消息摘要使用私钥进行署名,将署名后的消息发送给服务端。
- 服务端收到署名消息后,使用客户端公钥处理来得到摘要消息。对公共消息也使用sha256算法来提取摘要,对比摘要,成功则能够验证客户端的身份
流程图
一、流程图
二、tls_construct_cert_verify代码分析
- int tls_construct_cert_verify(SSL *s, WPACKET *pkt)
- {
- EVP_PKEY *pkey = NULL;
- const EVP_MD *md = NULL;
- EVP_MD_CTX *mctx = NULL;
- EVP_PKEY_CTX *pctx = NULL;
- size_t hdatalen = 0, siglen = 0;
- void *hdata;
- unsigned char *sig = NULL;
- unsigned char tls13tbs[TLS13_TBS_PREAMBLE_SIZE + EVP_MAX_MD_SIZE];
- const SIGALG_LOOKUP *lu = s->s3->tmp.sigalg;
- if (lu == NULL || s->s3->tmp.cert == NULL) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
- ERR_R_INTERNAL_ERROR);
- goto err;
- }
- pkey = s->s3->tmp.cert->privatekey;
- if (pkey == NULL || !tls1_lookup_md(lu, &md)) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
- ERR_R_INTERNAL_ERROR);
- goto err;
- }
- mctx = EVP_MD_CTX_new();
- if (mctx == NULL) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
- /* Get the data to be signed */
- if (!get_cert_verify_tbs_data(s, tls13tbs, &hdata, &hdatalen)) {
- /* SSLfatal() already called */
- goto err;
- }
- if (SSL_USE_SIGALGS(s) && !WPACKET_put_bytes_u16(pkt, lu->sigalg)) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
- ERR_R_INTERNAL_ERROR);
- goto err;
- }
- siglen = EVP_PKEY_size(pkey);
- sig = OPENSSL_malloc(siglen);
- if (sig == NULL) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
- ERR_R_MALLOC_FAILURE);
- goto err;
- }
- if (EVP_DigestSignInit(mctx, &pctx, md, NULL, pkey) <= 0) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
- ERR_R_EVP_LIB);
- goto err;
- }
- if (lu->sig == EVP_PKEY_RSA_PSS) {
- if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) <= 0
- || EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx,
- RSA_PSS_SALTLEN_DIGEST) <= 0) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
- ERR_R_EVP_LIB);
- goto err;
- }
- }
- if (s->version == SSL3_VERSION) {
- if (EVP_DigestSignUpdate(mctx, hdata, hdatalen) <= 0
- || !EVP_MD_CTX_ctrl(mctx, EVP_CTRL_SSL3_MASTER_SECRET,
- (int)s->session->master_key_length,
- s->session->master_key)
- || EVP_DigestSignFinal(mctx, sig, &siglen) <= 0) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
- ERR_R_EVP_LIB);
- goto err;
- }
- } else if (EVP_DigestSign(mctx, sig, &siglen, hdata, hdatalen) <= 0) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
- ERR_R_EVP_LIB);
- goto err;
- }
- #ifndef OPENSSL_NO_GOST
- {
- int pktype = lu->sig;
- if (pktype == NID_id_GostR3410_2001
- || pktype == NID_id_GostR3410_2012_256
- || pktype == NID_id_GostR3410_2012_512)
- BUF_reverse(sig, NULL, siglen);
- }
- #endif
- if (!WPACKET_sub_memcpy_u16(pkt, sig, siglen)) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
- ERR_R_INTERNAL_ERROR);
- goto err;
- }
- /* Digest cached records and discard handshake buffer */
- if (!ssl3_digest_cached_records(s, 0)) {
- /* SSLfatal() already called */
- goto err;
- }
- OPENSSL_free(sig);
- EVP_MD_CTX_free(mctx);
- return 1;
- err:
- OPENSSL_free(sig);
- EVP_MD_CTX_free(mctx);
- return 0;
- }
复制代码
- tls1_lookup_md(lu, &md)获取天生消息摘要的算法md。
- get_cert_verify_tbs_data(s, tls13tbs, &hdata, &hdatalen)天生待处理的数据hdata。
- EVP_DigestSignInit(mctx, &pctx, md, NULL, pkey)初始化
- EVP_DigestSign(mctx, sig, &siglen, hdata, hdatalen) 提取消息摘要,并进行署名
1.EVP_DigestSignInit(mctx, &pctx, md, NULL, pkey)初始化
- int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
- const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey)
- {
- return do_sigver_init(ctx, pctx, type, e, pkey, 0);
- }
- static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
- const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey,
- int ver)
- {
- if (ctx->pctx == NULL)
- ctx->pctx = EVP_PKEY_CTX_new(pkey, e);
- if (ctx->pctx == NULL)
- return 0;
- if (!(ctx->pctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM)) {
- if (type == NULL) {
- int def_nid;
- if (EVP_PKEY_get_default_digest_nid(pkey, &def_nid) > 0)
- type = EVP_get_digestbynid(def_nid);
- }
- if (type == NULL) {
- EVPerr(EVP_F_DO_SIGVER_INIT, EVP_R_NO_DEFAULT_DIGEST);
- return 0;
- }
- }
- if (ver) {
- if (ctx->pctx->pmeth->verifyctx_init) {
- if (ctx->pctx->pmeth->verifyctx_init(ctx->pctx, ctx) <= 0)
- return 0;
- ctx->pctx->operation = EVP_PKEY_OP_VERIFYCTX;
- } else if (ctx->pctx->pmeth->digestverify != 0) {
- ctx->pctx->operation = EVP_PKEY_OP_VERIFY;
- ctx->update = update;
- } else if (EVP_PKEY_verify_init(ctx->pctx) <= 0) {
- return 0;
- }
- } else {
- if (ctx->pctx->pmeth->signctx_init) {
- if (ctx->pctx->pmeth->signctx_init(ctx->pctx, ctx) <= 0)
- return 0;
- ctx->pctx->operation = EVP_PKEY_OP_SIGNCTX;
- } else if (ctx->pctx->pmeth->digestsign != 0) {
- ctx->pctx->operation = EVP_PKEY_OP_SIGN;
- ctx->update = update;
- } else if (EVP_PKEY_sign_init(ctx->pctx) <= 0) {
- return 0;
- }
- }
- if (EVP_PKEY_CTX_set_signature_md(ctx->pctx, type) <= 0)
- return 0;
- if (pctx)
- *pctx = ctx->pctx;
- if (ctx->pctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM)
- return 1;
- if (!EVP_DigestInit_ex(ctx, type, e))
- return 0;
- /*
- * This indicates the current algorithm requires
- * special treatment before hashing the tbs-message.
- */
- if (ctx->pctx->pmeth->digest_custom != NULL)
- return ctx->pctx->pmeth->digest_custom(ctx->pctx, ctx);
- return 1;
- }
复制代码 这里引入了2个概念EVP_MD_CTX 和EVP_PKEY_CTX
EVP_MD_CTX 是消息摘要上下文,包罗待署名的数据。
md_data既是其中的数据,当进行署名时,会更新md_data。
EVP_MD_CTX 包罗了EVP_PKEY_CTX
- struct evp_md_ctx_st {
- const EVP_MD *digest; //提取摘要消息的方法
- ENGINE *engine; //engine,如果有自定义的engine,则会赋该值
- unsigned long flags;
- void *md_data; //数据
- /* Public key context for sign/verify */
- EVP_PKEY_CTX *pctx; //EVP_PKEY_CTX对象
- /* Update function: usually copied from EVP_MD */
- //update方法,一般就是digest提取摘要消息的方法中的update。
- int (*update) (EVP_MD_CTX *ctx, const void *data, size_t count);
- }
复制代码
EVP_PKEY_CTX是密钥上下文,包罗了密钥和其他加密相关的信息。EVP_PKEY_CTX包罗了EVP_PKEY,即包罗了密钥对象pkey。
- struct evp_pkey_ctx_st {
- /* Method associated with this operation */
- const EVP_PKEY_METHOD *pmeth; //签名的方法
- /* Engine that implements this method or NULL if builtin */
- ENGINE *engine; //自定义的engine
- /* Key: may be NULL */
- EVP_PKEY *pkey; //私钥
- /* Peer key for key agreement, may be NULL */
- EVP_PKEY *peerkey;
- /* Actual operation */
- int operation;
- /* Algorithm specific data */
- void *data;
- /* Application specific data */
- void *app_data;
- /* Keygen callback */
- EVP_PKEY_gen_cb *pkey_gencb;
- /* implementation specific keygen data */
- int *keygen_info;
- int keygen_info_count;
- }
复制代码 EVP_PKEY是一个密钥的结构,可能包罗多种范例的密钥,好比EC、RSA、DSA等
- struct evp_pkey_st {
- int type;
- int save_type;
- CRYPTO_REF_COUNT references;
- const EVP_PKEY_ASN1_METHOD *ameth;
- ENGINE *engine;
- ENGINE *pmeth_engine; /* If not NULL public key ENGINE to use */
- union {
- void *ptr;
- # ifndef OPENSSL_NO_RSA
- struct rsa_st *rsa; /* RSA */
- # endif
- # ifndef OPENSSL_NO_DSA
- struct dsa_st *dsa; /* DSA */
- # endif
- # ifndef OPENSSL_NO_DH
- struct dh_st *dh; /* DH */
- # endif
- # ifndef OPENSSL_NO_EC
- struct ec_key_st *ec; /* ECC */
- ECX_KEY *ecx; /* X25519, X448, Ed25519, Ed448 */
- # endif
- } pkey;
- int save_parameters;
- STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */
- CRYPTO_RWLOCK *lock;
- }
复制代码 EVP_PKEY_CTX_new
do_sigver_init方法中首先调用了EVP_PKEY_CTX_new
- EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e)
- {
- return int_ctx_new(pkey, e, -1);
- }
- static EVP_PKEY_CTX *int_ctx_new(EVP_PKEY *pkey, ENGINE *e, int id)
- {
- EVP_PKEY_CTX *ret;
- const EVP_PKEY_METHOD *pmeth;
- if (id == -1) {
- if (pkey == NULL)
- return 0;
- id = pkey->type;
- }
- #ifndef OPENSSL_NO_ENGINE
- if (e == NULL && pkey != NULL)
- e = pkey->pmeth_engine != NULL ? pkey->pmeth_engine : pkey->engine;
- /* Try to find an ENGINE which implements this method */
- if (e) {
- if (!ENGINE_init(e)) {
- EVPerr(EVP_F_INT_CTX_NEW, ERR_R_ENGINE_LIB);
- return NULL;
- }
- } else {
- e = ENGINE_get_pkey_meth_engine(id);
- }
- /*
- * If an ENGINE handled this method look it up. Otherwise use internal
- * tables.
- */
- if (e)
- pmeth = ENGINE_get_pkey_meth(e, id);
- else
- #endif
- pmeth = EVP_PKEY_meth_find(id);
- if (pmeth == NULL) {
- #ifndef OPENSSL_NO_ENGINE
- ENGINE_finish(e);
- #endif
- EVPerr(EVP_F_INT_CTX_NEW, EVP_R_UNSUPPORTED_ALGORITHM);
- return NULL;
- }
- ret = OPENSSL_zalloc(sizeof(*ret));
- if (ret == NULL) {
- #ifndef OPENSSL_NO_ENGINE
- ENGINE_finish(e);
- #endif
- EVPerr(EVP_F_INT_CTX_NEW, ERR_R_MALLOC_FAILURE);
- return NULL;
- }
- ret->engine = e;
- ret->pmeth = pmeth;
- ret->operation = EVP_PKEY_OP_UNDEFINED;
- ret->pkey = pkey;
- if (pkey != NULL)
- EVP_PKEY_up_ref(pkey);
- if (pmeth->init) {
- if (pmeth->init(ret) <= 0) {
- ret->pmeth = NULL;
- EVP_PKEY_CTX_free(ret);
- return NULL;
- }
- }
- return ret;
- }
复制代码 由于这里的参数传入的engine为NULL,所以ENGINE_get_pkey_meth_engine(id);,这个方法会根据nid来查找是否存在实现了对应方法的engine。
由于在原生流程中没有该engine,那么调用pmeth = EVP_PKEY_meth_find(id);来根据nid查找EVP_PKEY_METHOD。EVP_PKEY_meth_find是根据nid来在standard_methods中查找默认的实现。这里由于是ecc的,所以返回的是&ec_pkey_meth。
得到了EVP_PKEY_METHOD后,便通过ret->pmeth = pmeth;来给EVP_PKEY_CTX中的pmeth 赋值。
即ctx->pctx->pmeth 便有值了。
EVP_PKEY_sign_init(ctx->pctx)
之后由于一些判断条件(原生的ec_pkey_meth没有signctx_init方法),便进入EVP_PKEY_sign_init(ctx->pctx)
- int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx)
- {
- int ret;
- if (!ctx || !ctx->pmeth || !ctx->pmeth->sign) {
- EVPerr(EVP_F_EVP_PKEY_SIGN_INIT,
- EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
- return -2;
- }
- ctx->operation = EVP_PKEY_OP_SIGN;
- if (!ctx->pmeth->sign_init)
- return 1;
- ret = ctx->pmeth->sign_init(ctx);
- if (ret <= 0)
- ctx->operation = EVP_PKEY_OP_UNDEFINED;
- return ret;
- }
复制代码 这里判断了pmeth中是否存在须要的sign方法,之后调用sign_init方法。
EVP_DigestInit_ex(ctx, type, e)
- int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
- {
- EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_CLEANED);
- #ifndef OPENSSL_NO_ENGINE
- /*
- * Whether it's nice or not, "Inits" can be used on "Final"'d contexts so
- * this context may already have an ENGINE! Try to avoid releasing the
- * previous handle, re-querying for an ENGINE, and having a
- * reinitialisation, when it may all be unnecessary.
- */
- if (ctx->engine && ctx->digest &&
- (type == NULL || (type->type == ctx->digest->type)))
- goto skip_to_init;
- if (type) {
- /*
- * Ensure an ENGINE left lying around from last time is cleared (the
- * previous check attempted to avoid this if the same ENGINE and
- * EVP_MD could be used).
- */
- ENGINE_finish(ctx->engine);
- if (impl != NULL) {
- if (!ENGINE_init(impl)) {
- EVPerr(EVP_F_EVP_DIGESTINIT_EX, EVP_R_INITIALIZATION_ERROR);
- return 0;
- }
- } else {
- /* Ask if an ENGINE is reserved for this job */
- impl = ENGINE_get_digest_engine(type->type);
- }
- if (impl != NULL) {
- /* There's an ENGINE for this job ... (apparently) */
- const EVP_MD *d = ENGINE_get_digest(impl, type->type);
- if (d == NULL) {
- EVPerr(EVP_F_EVP_DIGESTINIT_EX, EVP_R_INITIALIZATION_ERROR);
- ENGINE_finish(impl);
- return 0;
- }
- /* We'll use the ENGINE's private digest definition */
- type = d;
- /*
- * Store the ENGINE functional reference so we know 'type' came
- * from an ENGINE and we need to release it when done.
- */
- ctx->engine = impl;
- } else
- ctx->engine = NULL;
- } else {
- if (!ctx->digest) {
- EVPerr(EVP_F_EVP_DIGESTINIT_EX, EVP_R_NO_DIGEST_SET);
- return 0;
- }
- type = ctx->digest;
- }
- #endif
- if (ctx->digest != type) {
- if (ctx->digest && ctx->digest->ctx_size) {
- OPENSSL_clear_free(ctx->md_data, ctx->digest->ctx_size);
- ctx->md_data = NULL;
- }
- ctx->digest = type;
- if (!(ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) && type->ctx_size) {
- ctx->update = type->update;
- ctx->md_data = OPENSSL_zalloc(type->ctx_size);
- if (ctx->md_data == NULL) {
- EVPerr(EVP_F_EVP_DIGESTINIT_EX, ERR_R_MALLOC_FAILURE);
- return 0;
- }
- }
- }
- #ifndef OPENSSL_NO_ENGINE
- skip_to_init:
- #endif
- if (ctx->pctx) {
- int r;
- r = EVP_PKEY_CTX_ctrl(ctx->pctx, -1, EVP_PKEY_OP_TYPE_SIG,
- EVP_PKEY_CTRL_DIGESTINIT, 0, ctx);
- if (r <= 0 && (r != -2))
- return 0;
- }
- if (ctx->flags & EVP_MD_CTX_FLAG_NO_INIT)
- return 1;
- return ctx->digest->init(ctx);
- }
复制代码
- 这里由于没有传入自定义的engine,且系统内也没有对应nid的engine,所以直接跳到了ctx->digest = type;
- 是将ctx中的摘要方法进行赋值,这里是sha256方法。
- 之后的ctx->update = type->update;则是将ctx的update方法赋值为sha256的update方法。
- 最后调用了 ctx->digest->init(ctx);实际上是调用了sha256的init方法,注意,这里是提取摘要消息的开始。
2.EVP_DigestSign(mctx, sig, &siglen, hdata, hdatalen)
- int EVP_DigestSign(EVP_MD_CTX *ctx, unsigned char *sigret, size_t *siglen,
- const unsigned char *tbs, size_t tbslen)
- {
- if (ctx->pctx->pmeth->digestsign != NULL)
- return ctx->pctx->pmeth->digestsign(ctx, sigret, siglen, tbs, tbslen);
- if (sigret != NULL && EVP_DigestSignUpdate(ctx, tbs, tbslen) <= 0)
- return 0;
- return EVP_DigestSignFinal(ctx, sigret, siglen);
- }
复制代码 这里由于没有digestsign ,所以直接跳到EVP_DigestSignUpdate
EVP_DigestSignUpdate(ctx, tbs, tbslen)
- # define EVP_DigestSignUpdate(a,b,c) EVP_DigestUpdate(a,b,c)
- int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, size_t count)
- {
- return ctx->update(ctx, data, count);
- }
复制代码 这里是调用了ctx->update,前面的流程中我们给ctx->update赋值为了sha256的update方法,所以实际上调用了sha256的update方法,进行消息摘要的提取。
EVP_DigestSignFinal(ctx, sigret, siglen)
- int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret,
- size_t *siglen)
- {
- int sctx = 0, r = 0;
- EVP_PKEY_CTX *pctx = ctx->pctx;
- ...
- if (pctx->pmeth->signctx)
- sctx = 1;
- else
- sctx = 0;
- if (sigret) {
- unsigned char md[EVP_MAX_MD_SIZE];
- unsigned int mdlen = 0;
- if (ctx->flags & EVP_MD_CTX_FLAG_FINALISE) {
- if (sctx)
- r = ctx->pctx->pmeth->signctx(ctx->pctx, sigret, siglen, ctx);
- else
- r = EVP_DigestFinal_ex(ctx, md, &mdlen);
- } else {
- ......
- }
- if (sctx || !r)
- return r;
- if (EVP_PKEY_sign(ctx->pctx, sigret, siglen, md, mdlen) <= 0)
- return 0;
- } else {
- if (sctx) {
- if (pctx->pmeth->signctx(pctx, sigret, siglen, ctx) <= 0)
- return 0;
- } else {
- int s = EVP_MD_size(ctx->digest);
- if (s < 0 || EVP_PKEY_sign(pctx, sigret, siglen, NULL, s) <= 0)
- return 0;
- }
- }
- return 1;
- }
复制代码 依次调用了EVP_DigestFinal_ex(ctx, md, &mdlen)和EVP_PKEY_sign(ctx->pctx, sigret, siglen, md, mdlen)
EVP_DigestFinal_ex(ctx, md, &mdlen)
- int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size)
- {
- int ret;
- OPENSSL_assert(ctx->digest->md_size <= EVP_MAX_MD_SIZE);
- ret = ctx->digest->final(ctx, md);
- if (size != NULL)
- *size = ctx->digest->md_size;
- if (ctx->digest->cleanup) {
- ctx->digest->cleanup(ctx);
- EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_CLEANED);
- }
- OPENSSL_cleanse(ctx->md_data, ctx->digest->ctx_size);
- return ret;
- }
复制代码 这里调用了ctx->digest->final(ctx, md);,由于ctx->digest赋值为了sha256方法,所以这里实际调用了sha256的final方法,至此,依次调用了sha256的init、update和final,这就完成了消息摘要的提取的完整流程。
EVP_PKEY_sign(ctx->pctx, sigret, siglen, md, mdlen)
- int EVP_PKEY_sign(EVP_PKEY_CTX *ctx,
- unsigned char *sig, size_t *siglen,
- const unsigned char *tbs, size_t tbslen)
- {
- if (!ctx || !ctx->pmeth || !ctx->pmeth->sign) {
- EVPerr(EVP_F_EVP_PKEY_SIGN,
- EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
- return -2;
- }
- if (ctx->operation != EVP_PKEY_OP_SIGN) {
- EVPerr(EVP_F_EVP_PKEY_SIGN, EVP_R_OPERATON_NOT_INITIALIZED);
- return -1;
- }
- M_check_autoarg(ctx, sig, siglen, EVP_F_EVP_PKEY_SIGN)
- return ctx->pmeth->sign(ctx, sig, siglen, tbs, tbslen);
- }
复制代码 调用了ctx->pmeth->sign(ctx, sig, siglen, tbs, tbslen)方法。
ctx->pmeth是原生standard_methods中的默认&ec_pkey_meth实现。sign方法即为pkey_ec_sign方法
- static int pkey_ec_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
- const unsigned char *tbs, size_t tbslen)
- {
- int ret, type;
- unsigned int sltmp;
- EC_PKEY_CTX *dctx = ctx->data;
- EC_KEY *ec = ctx->pkey->pkey.ec;
- const int sig_sz = ECDSA_size(ec);
- /* ensure cast to size_t is safe */
- if (!ossl_assert(sig_sz > 0))
- return 0;
- if (sig == NULL) {
- *siglen = (size_t)sig_sz;
- return 1;
- }
- if (*siglen < (size_t)sig_sz) {
- ECerr(EC_F_PKEY_EC_SIGN, EC_R_BUFFER_TOO_SMALL);
- return 0;
- }
- type = (dctx->md != NULL) ? EVP_MD_type(dctx->md) : NID_sha1;
- ret = ECDSA_sign(type, tbs, tbslen, sig, &sltmp, ec);
- if (ret <= 0)
- return ret;
- *siglen = (size_t)sltmp;
- return 1;
- }
复制代码 pkey_ec_sign中调用ECDSA_sign(type, tbs, tbslen, sig, &sltmp, ec)来对摘要消息进行署名。
至此,完成了摘要消息的提取以及署名的流程。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |