[openSSL]tls_construct_cert_verify署名流程

打印 上一主题 下一主题

主题 995|帖子 995|积分 2987


前言

tls_construct_cert_verify是openSSL源码中的一个方法,用于进行TLS握手阶段的署名流程。
从概念上讲,数字署名的流程是如许的:

  • 客户端根据一段公共消息天生消息摘要,一样平常是使用sha256算法。
  • 客户端对消息摘要使用私钥进行署名,将署名后的消息发送给服务端。
  • 服务端收到署名消息后,使用客户端公钥处理来得到摘要消息。对公共消息也使用sha256算法来提取摘要,对比摘要,成功则能够验证客户端的身份
流程图
一、流程图


二、tls_construct_cert_verify代码分析

  1. int tls_construct_cert_verify(SSL *s, WPACKET *pkt)
  2. {
  3.     EVP_PKEY *pkey = NULL;
  4.     const EVP_MD *md = NULL;
  5.     EVP_MD_CTX *mctx = NULL;
  6.     EVP_PKEY_CTX *pctx = NULL;
  7.     size_t hdatalen = 0, siglen = 0;
  8.     void *hdata;
  9.     unsigned char *sig = NULL;
  10.     unsigned char tls13tbs[TLS13_TBS_PREAMBLE_SIZE + EVP_MAX_MD_SIZE];
  11.     const SIGALG_LOOKUP *lu = s->s3->tmp.sigalg;
  12.     if (lu == NULL || s->s3->tmp.cert == NULL) {
  13.         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
  14.                  ERR_R_INTERNAL_ERROR);
  15.         goto err;
  16.     }
  17.     pkey = s->s3->tmp.cert->privatekey;
  18.     if (pkey == NULL || !tls1_lookup_md(lu, &md)) {
  19.         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
  20.                  ERR_R_INTERNAL_ERROR);
  21.         goto err;
  22.     }
  23.     mctx = EVP_MD_CTX_new();
  24.     if (mctx == NULL) {
  25.         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
  26.                  ERR_R_MALLOC_FAILURE);
  27.         goto err;
  28.     }
  29.     /* Get the data to be signed */
  30.     if (!get_cert_verify_tbs_data(s, tls13tbs, &hdata, &hdatalen)) {
  31.         /* SSLfatal() already called */
  32.         goto err;
  33.     }
  34.     if (SSL_USE_SIGALGS(s) && !WPACKET_put_bytes_u16(pkt, lu->sigalg)) {
  35.         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
  36.                  ERR_R_INTERNAL_ERROR);
  37.         goto err;
  38.     }
  39.     siglen = EVP_PKEY_size(pkey);
  40.     sig = OPENSSL_malloc(siglen);
  41.     if (sig == NULL) {
  42.         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
  43.                  ERR_R_MALLOC_FAILURE);
  44.         goto err;
  45.     }
  46.     if (EVP_DigestSignInit(mctx, &pctx, md, NULL, pkey) <= 0) {
  47.         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
  48.                  ERR_R_EVP_LIB);
  49.         goto err;
  50.     }
  51.     if (lu->sig == EVP_PKEY_RSA_PSS) {
  52.         if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) <= 0
  53.             || EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx,
  54.                                                 RSA_PSS_SALTLEN_DIGEST) <= 0) {
  55.             SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
  56.                      ERR_R_EVP_LIB);
  57.             goto err;
  58.         }
  59.     }
  60.     if (s->version == SSL3_VERSION) {
  61.         if (EVP_DigestSignUpdate(mctx, hdata, hdatalen) <= 0
  62.             || !EVP_MD_CTX_ctrl(mctx, EVP_CTRL_SSL3_MASTER_SECRET,
  63.                                 (int)s->session->master_key_length,
  64.                                 s->session->master_key)
  65.             || EVP_DigestSignFinal(mctx, sig, &siglen) <= 0) {
  66.             SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
  67.                      ERR_R_EVP_LIB);
  68.             goto err;
  69.         }
  70.     } else if (EVP_DigestSign(mctx, sig, &siglen, hdata, hdatalen) <= 0) {
  71.         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
  72.                  ERR_R_EVP_LIB);
  73.         goto err;
  74.     }
  75. #ifndef OPENSSL_NO_GOST
  76.     {
  77.         int pktype = lu->sig;
  78.         if (pktype == NID_id_GostR3410_2001
  79.             || pktype == NID_id_GostR3410_2012_256
  80.             || pktype == NID_id_GostR3410_2012_512)
  81.             BUF_reverse(sig, NULL, siglen);
  82.     }
  83. #endif
  84.     if (!WPACKET_sub_memcpy_u16(pkt, sig, siglen)) {
  85.         SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
  86.                  ERR_R_INTERNAL_ERROR);
  87.         goto err;
  88.     }
  89.     /* Digest cached records and discard handshake buffer */
  90.     if (!ssl3_digest_cached_records(s, 0)) {
  91.         /* SSLfatal() already called */
  92.         goto err;
  93.     }
  94.     OPENSSL_free(sig);
  95.     EVP_MD_CTX_free(mctx);
  96.     return 1;
  97. err:
  98.     OPENSSL_free(sig);
  99.     EVP_MD_CTX_free(mctx);
  100.     return 0;
  101. }
复制代码

  • 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)初始化

  1. int EVP_DigestSignInit(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
  2.                        const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey)
  3. {
  4.     return do_sigver_init(ctx, pctx, type, e, pkey, 0);
  5. }
  6. static int do_sigver_init(EVP_MD_CTX *ctx, EVP_PKEY_CTX **pctx,
  7.                           const EVP_MD *type, ENGINE *e, EVP_PKEY *pkey,
  8.                           int ver)
  9. {
  10.     if (ctx->pctx == NULL)
  11.         ctx->pctx = EVP_PKEY_CTX_new(pkey, e);
  12.     if (ctx->pctx == NULL)
  13.         return 0;
  14.     if (!(ctx->pctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM)) {
  15.         if (type == NULL) {
  16.             int def_nid;
  17.             if (EVP_PKEY_get_default_digest_nid(pkey, &def_nid) > 0)
  18.                 type = EVP_get_digestbynid(def_nid);
  19.         }
  20.         if (type == NULL) {
  21.             EVPerr(EVP_F_DO_SIGVER_INIT, EVP_R_NO_DEFAULT_DIGEST);
  22.             return 0;
  23.         }
  24.     }
  25.     if (ver) {
  26.         if (ctx->pctx->pmeth->verifyctx_init) {
  27.             if (ctx->pctx->pmeth->verifyctx_init(ctx->pctx, ctx) <= 0)
  28.                 return 0;
  29.             ctx->pctx->operation = EVP_PKEY_OP_VERIFYCTX;
  30.         } else if (ctx->pctx->pmeth->digestverify != 0) {
  31.             ctx->pctx->operation = EVP_PKEY_OP_VERIFY;
  32.             ctx->update = update;
  33.         } else if (EVP_PKEY_verify_init(ctx->pctx) <= 0) {
  34.             return 0;
  35.         }
  36.     } else {
  37.         if (ctx->pctx->pmeth->signctx_init) {
  38.             if (ctx->pctx->pmeth->signctx_init(ctx->pctx, ctx) <= 0)
  39.                 return 0;
  40.             ctx->pctx->operation = EVP_PKEY_OP_SIGNCTX;
  41.         } else if (ctx->pctx->pmeth->digestsign != 0) {
  42.             ctx->pctx->operation = EVP_PKEY_OP_SIGN;
  43.             ctx->update = update;
  44.         } else if (EVP_PKEY_sign_init(ctx->pctx) <= 0) {
  45.             return 0;
  46.         }
  47.     }
  48.     if (EVP_PKEY_CTX_set_signature_md(ctx->pctx, type) <= 0)
  49.         return 0;
  50.     if (pctx)
  51.         *pctx = ctx->pctx;
  52.     if (ctx->pctx->pmeth->flags & EVP_PKEY_FLAG_SIGCTX_CUSTOM)
  53.         return 1;
  54.     if (!EVP_DigestInit_ex(ctx, type, e))
  55.         return 0;
  56.     /*
  57.      * This indicates the current algorithm requires
  58.      * special treatment before hashing the tbs-message.
  59.      */
  60.     if (ctx->pctx->pmeth->digest_custom != NULL)
  61.         return ctx->pctx->pmeth->digest_custom(ctx->pctx, ctx);
  62.     return 1;
  63. }
复制代码
这里引入了2个概念EVP_MD_CTX 和EVP_PKEY_CTX
EVP_MD_CTX 是消息摘要上下文,包罗待署名的数据。
md_data既是其中的数据,当进行署名时,会更新md_data。
EVP_MD_CTX 包罗了EVP_PKEY_CTX
  1. struct evp_md_ctx_st {
  2.     const EVP_MD *digest;       //提取摘要消息的方法
  3.     ENGINE *engine;             //engine,如果有自定义的engine,则会赋该值
  4.     unsigned long flags;
  5.     void *md_data;              //数据
  6.     /* Public key context for sign/verify */
  7.     EVP_PKEY_CTX *pctx;         //EVP_PKEY_CTX对象
  8.     /* Update function: usually copied from EVP_MD */
  9.     //update方法,一般就是digest提取摘要消息的方法中的update。
  10.     int (*update) (EVP_MD_CTX *ctx, const void *data, size_t count);
  11. }
复制代码



EVP_PKEY_CTX是密钥上下文,包罗了密钥和其他加密相关的信息。EVP_PKEY_CTX包罗了EVP_PKEY,即包罗了密钥对象pkey。
  1. struct evp_pkey_ctx_st {
  2.     /* Method associated with this operation */
  3.     const EVP_PKEY_METHOD *pmeth;       //签名的方法
  4.     /* Engine that implements this method or NULL if builtin */
  5.     ENGINE *engine;                     //自定义的engine
  6.     /* Key: may be NULL */
  7.     EVP_PKEY *pkey;                     //私钥
  8.     /* Peer key for key agreement, may be NULL */
  9.     EVP_PKEY *peerkey;
  10.     /* Actual operation */
  11.     int operation;
  12.     /* Algorithm specific data */
  13.     void *data;
  14.     /* Application specific data */
  15.     void *app_data;
  16.     /* Keygen callback */
  17.     EVP_PKEY_gen_cb *pkey_gencb;
  18.     /* implementation specific keygen data */
  19.     int *keygen_info;
  20.     int keygen_info_count;
  21. }
复制代码
EVP_PKEY是一个密钥的结构,可能包罗多种范例的密钥,好比EC、RSA、DSA等
  1. struct evp_pkey_st {
  2.     int type;
  3.     int save_type;
  4.     CRYPTO_REF_COUNT references;
  5.     const EVP_PKEY_ASN1_METHOD *ameth;
  6.     ENGINE *engine;
  7.     ENGINE *pmeth_engine; /* If not NULL public key ENGINE to use */
  8.     union {
  9.         void *ptr;
  10. # ifndef OPENSSL_NO_RSA
  11.         struct rsa_st *rsa;     /* RSA */
  12. # endif
  13. # ifndef OPENSSL_NO_DSA
  14.         struct dsa_st *dsa;     /* DSA */
  15. # endif
  16. # ifndef OPENSSL_NO_DH
  17.         struct dh_st *dh;       /* DH */
  18. # endif
  19. # ifndef OPENSSL_NO_EC
  20.         struct ec_key_st *ec;   /* ECC */
  21.         ECX_KEY *ecx;           /* X25519, X448, Ed25519, Ed448 */
  22. # endif
  23.     } pkey;
  24.     int save_parameters;
  25.     STACK_OF(X509_ATTRIBUTE) *attributes; /* [ 0 ] */
  26.     CRYPTO_RWLOCK *lock;
  27. }
复制代码
EVP_PKEY_CTX_new

do_sigver_init方法中首先调用了EVP_PKEY_CTX_new
  1. EVP_PKEY_CTX *EVP_PKEY_CTX_new(EVP_PKEY *pkey, ENGINE *e)
  2. {
  3.     return int_ctx_new(pkey, e, -1);
  4. }
  5. static EVP_PKEY_CTX *int_ctx_new(EVP_PKEY *pkey, ENGINE *e, int id)
  6. {
  7.     EVP_PKEY_CTX *ret;
  8.     const EVP_PKEY_METHOD *pmeth;
  9.     if (id == -1) {
  10.         if (pkey == NULL)
  11.             return 0;
  12.         id = pkey->type;
  13.     }
  14. #ifndef OPENSSL_NO_ENGINE
  15.     if (e == NULL && pkey != NULL)
  16.         e = pkey->pmeth_engine != NULL ? pkey->pmeth_engine : pkey->engine;
  17.     /* Try to find an ENGINE which implements this method */
  18.     if (e) {
  19.         if (!ENGINE_init(e)) {
  20.             EVPerr(EVP_F_INT_CTX_NEW, ERR_R_ENGINE_LIB);
  21.             return NULL;
  22.         }
  23.     } else {
  24.         e = ENGINE_get_pkey_meth_engine(id);
  25.     }
  26.     /*
  27.      * If an ENGINE handled this method look it up. Otherwise use internal
  28.      * tables.
  29.      */
  30.     if (e)
  31.         pmeth = ENGINE_get_pkey_meth(e, id);
  32.     else
  33. #endif
  34.         pmeth = EVP_PKEY_meth_find(id);
  35.     if (pmeth == NULL) {
  36. #ifndef OPENSSL_NO_ENGINE
  37.         ENGINE_finish(e);
  38. #endif
  39.         EVPerr(EVP_F_INT_CTX_NEW, EVP_R_UNSUPPORTED_ALGORITHM);
  40.         return NULL;
  41.     }
  42.     ret = OPENSSL_zalloc(sizeof(*ret));
  43.     if (ret == NULL) {
  44. #ifndef OPENSSL_NO_ENGINE
  45.         ENGINE_finish(e);
  46. #endif
  47.         EVPerr(EVP_F_INT_CTX_NEW, ERR_R_MALLOC_FAILURE);
  48.         return NULL;
  49.     }
  50.     ret->engine = e;
  51.     ret->pmeth = pmeth;
  52.     ret->operation = EVP_PKEY_OP_UNDEFINED;
  53.     ret->pkey = pkey;
  54.     if (pkey != NULL)
  55.         EVP_PKEY_up_ref(pkey);
  56.     if (pmeth->init) {
  57.         if (pmeth->init(ret) <= 0) {
  58.             ret->pmeth = NULL;
  59.             EVP_PKEY_CTX_free(ret);
  60.             return NULL;
  61.         }
  62.     }
  63.     return ret;
  64. }
复制代码
由于这里的参数传入的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)
  1. int EVP_PKEY_sign_init(EVP_PKEY_CTX *ctx)
  2. {
  3.     int ret;
  4.     if (!ctx || !ctx->pmeth || !ctx->pmeth->sign) {
  5.         EVPerr(EVP_F_EVP_PKEY_SIGN_INIT,
  6.                EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
  7.         return -2;
  8.     }
  9.     ctx->operation = EVP_PKEY_OP_SIGN;
  10.     if (!ctx->pmeth->sign_init)
  11.         return 1;
  12.     ret = ctx->pmeth->sign_init(ctx);
  13.     if (ret <= 0)
  14.         ctx->operation = EVP_PKEY_OP_UNDEFINED;
  15.     return ret;
  16. }
复制代码
这里判断了pmeth中是否存在须要的sign方法,之后调用sign_init方法。
EVP_DigestInit_ex(ctx, type, e)

  1. int EVP_DigestInit_ex(EVP_MD_CTX *ctx, const EVP_MD *type, ENGINE *impl)
  2. {
  3.     EVP_MD_CTX_clear_flags(ctx, EVP_MD_CTX_FLAG_CLEANED);
  4. #ifndef OPENSSL_NO_ENGINE
  5.     /*
  6.      * Whether it's nice or not, "Inits" can be used on "Final"'d contexts so
  7.      * this context may already have an ENGINE! Try to avoid releasing the
  8.      * previous handle, re-querying for an ENGINE, and having a
  9.      * reinitialisation, when it may all be unnecessary.
  10.      */
  11.     if (ctx->engine && ctx->digest &&
  12.         (type == NULL || (type->type == ctx->digest->type)))
  13.         goto skip_to_init;
  14.     if (type) {
  15.         /*
  16.          * Ensure an ENGINE left lying around from last time is cleared (the
  17.          * previous check attempted to avoid this if the same ENGINE and
  18.          * EVP_MD could be used).
  19.          */
  20.         ENGINE_finish(ctx->engine);
  21.         if (impl != NULL) {
  22.             if (!ENGINE_init(impl)) {
  23.                 EVPerr(EVP_F_EVP_DIGESTINIT_EX, EVP_R_INITIALIZATION_ERROR);
  24.                 return 0;
  25.             }
  26.         } else {
  27.             /* Ask if an ENGINE is reserved for this job */
  28.             impl = ENGINE_get_digest_engine(type->type);
  29.         }
  30.         if (impl != NULL) {
  31.             /* There's an ENGINE for this job ... (apparently) */
  32.             const EVP_MD *d = ENGINE_get_digest(impl, type->type);
  33.             if (d == NULL) {
  34.                 EVPerr(EVP_F_EVP_DIGESTINIT_EX, EVP_R_INITIALIZATION_ERROR);
  35.                 ENGINE_finish(impl);
  36.                 return 0;
  37.             }
  38.             /* We'll use the ENGINE's private digest definition */
  39.             type = d;
  40.             /*
  41.              * Store the ENGINE functional reference so we know 'type' came
  42.              * from an ENGINE and we need to release it when done.
  43.              */
  44.             ctx->engine = impl;
  45.         } else
  46.             ctx->engine = NULL;
  47.     } else {
  48.         if (!ctx->digest) {
  49.             EVPerr(EVP_F_EVP_DIGESTINIT_EX, EVP_R_NO_DIGEST_SET);
  50.             return 0;
  51.         }
  52.         type = ctx->digest;
  53.     }
  54. #endif
  55.     if (ctx->digest != type) {
  56.         if (ctx->digest && ctx->digest->ctx_size) {
  57.             OPENSSL_clear_free(ctx->md_data, ctx->digest->ctx_size);
  58.             ctx->md_data = NULL;
  59.         }
  60.         ctx->digest = type;
  61.         if (!(ctx->flags & EVP_MD_CTX_FLAG_NO_INIT) && type->ctx_size) {
  62.             ctx->update = type->update;
  63.             ctx->md_data = OPENSSL_zalloc(type->ctx_size);
  64.             if (ctx->md_data == NULL) {
  65.                 EVPerr(EVP_F_EVP_DIGESTINIT_EX, ERR_R_MALLOC_FAILURE);
  66.                 return 0;
  67.             }
  68.         }
  69.     }
  70. #ifndef OPENSSL_NO_ENGINE
  71. skip_to_init:
  72. #endif
  73.     if (ctx->pctx) {
  74.         int r;
  75.         r = EVP_PKEY_CTX_ctrl(ctx->pctx, -1, EVP_PKEY_OP_TYPE_SIG,
  76.                               EVP_PKEY_CTRL_DIGESTINIT, 0, ctx);
  77.         if (r <= 0 && (r != -2))
  78.             return 0;
  79.     }
  80.     if (ctx->flags & EVP_MD_CTX_FLAG_NO_INIT)
  81.         return 1;
  82.     return ctx->digest->init(ctx);
  83. }
复制代码

  • 这里由于没有传入自定义的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)

  1. int EVP_DigestSign(EVP_MD_CTX *ctx, unsigned char *sigret, size_t *siglen,
  2.                    const unsigned char *tbs, size_t tbslen)
  3. {
  4.     if (ctx->pctx->pmeth->digestsign != NULL)
  5.         return ctx->pctx->pmeth->digestsign(ctx, sigret, siglen, tbs, tbslen);
  6.     if (sigret != NULL && EVP_DigestSignUpdate(ctx, tbs, tbslen) <= 0)
  7.         return 0;
  8.     return EVP_DigestSignFinal(ctx, sigret, siglen);
  9. }
复制代码
这里由于没有digestsign ,所以直接跳到EVP_DigestSignUpdate
EVP_DigestSignUpdate(ctx, tbs, tbslen)

  1. # define EVP_DigestSignUpdate(a,b,c)     EVP_DigestUpdate(a,b,c)
  2. int EVP_DigestUpdate(EVP_MD_CTX *ctx, const void *data, size_t count)
  3. {
  4.     return ctx->update(ctx, data, count);
  5. }
复制代码
这里是调用了ctx->update,前面的流程中我们给ctx->update赋值为了sha256的update方法,所以实际上调用了sha256的update方法,进行消息摘要的提取。
EVP_DigestSignFinal(ctx, sigret, siglen)

  1. int EVP_DigestSignFinal(EVP_MD_CTX *ctx, unsigned char *sigret,
  2.                         size_t *siglen)
  3. {
  4.     int sctx = 0, r = 0;
  5.     EVP_PKEY_CTX *pctx = ctx->pctx;
  6.     ...
  7.     if (pctx->pmeth->signctx)
  8.         sctx = 1;
  9.     else
  10.         sctx = 0;
  11.     if (sigret) {
  12.         unsigned char md[EVP_MAX_MD_SIZE];
  13.         unsigned int mdlen = 0;
  14.         if (ctx->flags & EVP_MD_CTX_FLAG_FINALISE) {
  15.             if (sctx)
  16.                 r = ctx->pctx->pmeth->signctx(ctx->pctx, sigret, siglen, ctx);
  17.             else
  18.                 r = EVP_DigestFinal_ex(ctx, md, &mdlen);
  19.         } else {
  20.             ......
  21.         }
  22.         if (sctx || !r)
  23.             return r;
  24.         if (EVP_PKEY_sign(ctx->pctx, sigret, siglen, md, mdlen) <= 0)
  25.             return 0;
  26.     } else {
  27.         if (sctx) {
  28.             if (pctx->pmeth->signctx(pctx, sigret, siglen, ctx) <= 0)
  29.                 return 0;
  30.         } else {
  31.             int s = EVP_MD_size(ctx->digest);
  32.             if (s < 0 || EVP_PKEY_sign(pctx, sigret, siglen, NULL, s) <= 0)
  33.                 return 0;
  34.         }
  35.     }
  36.     return 1;
  37. }
复制代码
依次调用了EVP_DigestFinal_ex(ctx, md, &mdlen)和EVP_PKEY_sign(ctx->pctx, sigret, siglen, md, mdlen)
EVP_DigestFinal_ex(ctx, md, &mdlen)

  1. int EVP_DigestFinal_ex(EVP_MD_CTX *ctx, unsigned char *md, unsigned int *size)
  2. {
  3.     int ret;
  4.     OPENSSL_assert(ctx->digest->md_size <= EVP_MAX_MD_SIZE);
  5.     ret = ctx->digest->final(ctx, md);
  6.     if (size != NULL)
  7.         *size = ctx->digest->md_size;
  8.     if (ctx->digest->cleanup) {
  9.         ctx->digest->cleanup(ctx);
  10.         EVP_MD_CTX_set_flags(ctx, EVP_MD_CTX_FLAG_CLEANED);
  11.     }
  12.     OPENSSL_cleanse(ctx->md_data, ctx->digest->ctx_size);
  13.     return ret;
  14. }
复制代码
这里调用了ctx->digest->final(ctx, md);,由于ctx->digest赋值为了sha256方法,所以这里实际调用了sha256的final方法,至此,依次调用了sha256的init、update和final,这就完成了消息摘要的提取的完整流程。
EVP_PKEY_sign(ctx->pctx, sigret, siglen, md, mdlen)

  1. int EVP_PKEY_sign(EVP_PKEY_CTX *ctx,
  2.                   unsigned char *sig, size_t *siglen,
  3.                   const unsigned char *tbs, size_t tbslen)
  4. {
  5.     if (!ctx || !ctx->pmeth || !ctx->pmeth->sign) {
  6.         EVPerr(EVP_F_EVP_PKEY_SIGN,
  7.                EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
  8.         return -2;
  9.     }
  10.     if (ctx->operation != EVP_PKEY_OP_SIGN) {
  11.         EVPerr(EVP_F_EVP_PKEY_SIGN, EVP_R_OPERATON_NOT_INITIALIZED);
  12.         return -1;
  13.     }
  14.     M_check_autoarg(ctx, sig, siglen, EVP_F_EVP_PKEY_SIGN)
  15.         return ctx->pmeth->sign(ctx, sig, siglen, tbs, tbslen);
  16. }
复制代码
调用了ctx->pmeth->sign(ctx, sig, siglen, tbs, tbslen)方法。
ctx->pmeth是原生standard_methods中的默认&ec_pkey_meth实现。sign方法即为pkey_ec_sign方法
  1. static int pkey_ec_sign(EVP_PKEY_CTX *ctx, unsigned char *sig, size_t *siglen,
  2.                         const unsigned char *tbs, size_t tbslen)
  3. {
  4.     int ret, type;
  5.     unsigned int sltmp;
  6.     EC_PKEY_CTX *dctx = ctx->data;
  7.     EC_KEY *ec = ctx->pkey->pkey.ec;
  8.     const int sig_sz = ECDSA_size(ec);
  9.     /* ensure cast to size_t is safe */
  10.     if (!ossl_assert(sig_sz > 0))
  11.         return 0;
  12.     if (sig == NULL) {
  13.         *siglen = (size_t)sig_sz;
  14.         return 1;
  15.     }
  16.     if (*siglen < (size_t)sig_sz) {
  17.         ECerr(EC_F_PKEY_EC_SIGN, EC_R_BUFFER_TOO_SMALL);
  18.         return 0;
  19.     }
  20.     type = (dctx->md != NULL) ? EVP_MD_type(dctx->md) : NID_sha1;
  21.     ret = ECDSA_sign(type, tbs, tbslen, sig, &sltmp, ec);
  22.     if (ret <= 0)
  23.         return ret;
  24.     *siglen = (size_t)sltmp;
  25.     return 1;
  26. }
复制代码
pkey_ec_sign中调用ECDSA_sign(type, tbs, tbslen, sig, &sltmp, ec)来对摘要消息进行署名。
至此,完成了摘要消息的提取以及署名的流程。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

tsx81428

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表