static ECDSA_SIG *pkcs11_ecdsa_sign(const unsigned char *dgst, int dgst_len, const BIGNUM *inv, const BIGNUM *rp, EC_KEY *ecdsa) { struct pkcs11_key_data *pkd = NULL; CK_MECHANISM mech = { CKM_ECDSA, NULL_PTR, 0 }; CK_ULONG tlen = 0; CK_RV rv; #if OPENSSL_VERSION_NUMBER < 0x10100000L pkd = ECDSA_get_ex_data(ecdsa, pkcs11_ecdsa_key_idx); #else pkd = EC_KEY_get_ex_data(ecdsa, pkcs11_ecdsa_key_idx); #endif if((pkd != NULL) && ((rv = pkd->funcs->C_SignInit(pkd->session, &mech, pkd->key)) == CKR_OK)) { CK_BYTE_PTR buf = NULL; ECDSA_SIG *rval; BIGNUM *r, *s; int nlen; /* Make a call to C_Sign to find out the size of the signature */ rv = pkd->funcs->C_Sign(pkd->session, (CK_BYTE *)dgst, dgst_len, NULL, &tlen); if (rv != CKR_OK) { return NULL; } if ((buf = malloc(tlen)) == NULL) { return NULL; } rv = pkd->funcs->C_Sign(pkd->session, (CK_BYTE *)dgst, dgst_len, buf, &tlen); if (rv != CKR_OK) { free(buf); return NULL; } if ((rval = ECDSA_SIG_new()) != NULL) { /* * ECDSA signature is 2 large integers of same size returned * concatenated by PKCS#11, we separate them to create an * ECDSA_SIG for OpenSSL. */ nlen = tlen / 2; #if OPENSSL_VERSION_NUMBER >= 0x10100000L ECDSA_SIG_get0(&r, &s, rval); #else r = rval->r; s = rval->s; #endif BN_bin2bn(&buf[0], nlen, r); BN_bin2bn(&buf[nlen], nlen, s); } free(buf); return rval; } else { return NULL; } }
int _libssh2_ecdsa_sign(LIBSSH2_SESSION * session, libssh2_ecdsa_ctx * ec_ctx, const unsigned char *hash, unsigned long hash_len, unsigned char **signature, size_t *signature_len) { int r_len, s_len; int rc = 0; size_t out_buffer_len = 0; unsigned char *sp; const BIGNUM *pr = NULL, *ps = NULL; unsigned char *temp_buffer = NULL; unsigned char *out_buffer = NULL; ECDSA_SIG *sig = ECDSA_do_sign(hash, hash_len, ec_ctx); if(sig == NULL) return -1; #ifdef HAVE_OPAQUE_STRUCTS ECDSA_SIG_get0(sig, &pr, &ps); #else pr = sig->r; ps = sig->s; #endif r_len = BN_num_bytes(pr) + 1; s_len = BN_num_bytes(ps) + 1; temp_buffer = malloc(r_len + s_len + 8); if(temp_buffer == NULL) { rc = -1; goto clean_exit; } sp = temp_buffer; sp = write_bn(sp, pr, r_len); sp = write_bn(sp, ps, s_len); out_buffer_len = (size_t)(sp - temp_buffer); out_buffer = LIBSSH2_CALLOC(session, out_buffer_len); if(out_buffer == NULL) { rc = -1; goto clean_exit; } memcpy(out_buffer, temp_buffer, out_buffer_len); *signature = out_buffer; *signature_len = out_buffer_len; clean_exit: if(temp_buffer != NULL) free(temp_buffer); if(sig) ECDSA_SIG_free(sig); return rc; }
static ECDSA_SIG * pkcs11_ecdsa_do_sign(const unsigned char *dgst, int dlen, const BIGNUM *inv, const BIGNUM *r, EC_KEY * ec) { unsigned char sigret[512]; /* HACK for now */ ECDSA_SIG * sig = NULL; PKCS11_KEY * key = NULL; unsigned int siglen; int nLen = 48; /* HACK */ int rv; #if OPENSSL_VERSION_NUMBER >= 0x10100000L key = (PKCS11_KEY *) EC_KEY_get_ex_data(ec, ec_key_ex_index); #else key = (PKCS11_KEY *) ECDSA_get_ex_data(ec, ecdsa_ex_index); #endif if (key == NULL) return NULL; siglen = sizeof(sigret); rv = PKCS11_ecdsa_sign(dgst, dlen, sigret, &siglen, key); nLen = siglen / 2; if (rv > 0) { sig = ECDSA_SIG_new(); if (sig) { #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* * OpenSSL 1.1 does not have a way to allocate r and s * in ECDSA_SIG as it is now hidden. * Will us dummy ASN1 so r and s are allocated then * use ECDSA_SIG_get0 to get access to r and s * can then update r annd s */ const unsigned char *a; unsigned char dasn1[8] = {0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00}; BIGNUM *r; BIGNUM *s; a = dasn1; d2i_ECDSA_SIG(&sig, &a, 8); ECDSA_SIG_get0(&r, &s, sig); BN_bin2bn(&sigret[0], nLen, r); BN_bin2bn(&sigret[nLen], nLen, s); #else BN_bin2bn(&sigret[0], nLen, sig->r); BN_bin2bn(&sigret[nLen], nLen, sig->s); #endif } } return sig; }
/** * ECDSA signing method (replaces ossl_ecdsa_sign_sig) * * @param dgst hash value to sign * @param dlen length of the hash value * @param kinv precomputed inverse k (from the sign_setup method) * @param rp precomputed rp (from the sign_setup method) * @param ec private EC signing key * @return pointer to a ECDSA_SIG structure or NULL if an error occurred */ static ECDSA_SIG *pkcs11_ecdsa_sign_sig(const unsigned char *dgst, int dlen, const BIGNUM *kinv, const BIGNUM *rp, EC_KEY *ec) { unsigned char sigret[512]; /* HACK for now */ ECDSA_SIG *sig; PKCS11_KEY *key; unsigned int siglen; BIGNUM *r, *s, *order; (void)kinv; /* Precomputed values are not used for PKCS#11 */ (void)rp; /* Precomputed values are not used for PKCS#11 */ #if OPENSSL_VERSION_NUMBER >= 0x10100000L key = (PKCS11_KEY *)EC_KEY_get_ex_data(ec, ec_ex_index); #else key = (PKCS11_KEY *)ECDSA_get_ex_data(ec, ec_ex_index); #endif if (key == NULL) { PKCS11err(PKCS11_F_PKCS11_EC_KEY_SIGN, PKCS11_ALIEN_KEY); return NULL; } /* TODO: Add an atfork check */ /* Truncate digest if its byte size is longer than needed */ order = BN_new(); if (order) { const EC_GROUP *group = EC_KEY_get0_group(ec); if (group && EC_GROUP_get_order(group, order, NULL)) { int klen = BN_num_bits(order); if (klen < 8*dlen) dlen = (klen+7)/8; } BN_free(order); } siglen = sizeof sigret; if (pkcs11_ecdsa_sign(dgst, dlen, sigret, &siglen, key) <= 0) return NULL; sig = ECDSA_SIG_new(); if (sig == NULL) return NULL; #if OPENSSL_VERSION_NUMBER >= 0x10100000L ECDSA_SIG_get0(&r, &s, sig); #else r = sig->r; s = sig->s; #endif BN_bin2bn(sigret, siglen/2, r); BN_bin2bn(sigret + siglen/2, siglen/2, s); return sig; }
// create a compact signature (65 bytes), which allows reconstructing the used public key // The format is one header byte, followed by two times 32 bytes for the serialized r and s values. // The header byte: 0x1B = first key with even y, 0x1C = first key with odd y, // 0x1D = second key with even y, 0x1E = second key with odd y bool CKey::SignCompact(uint256 hash, std::vector<unsigned char>& vchSig) { bool fOk = false; ECDSA_SIG *sig = ECDSA_do_sign((unsigned char*)&hash, sizeof(hash), pkey); if (sig==NULL) return false; vchSig.clear(); vchSig.resize(65,0); const BIGNUM *sig_r, *sig_s; #if OPENSSL_VERSION_NUMBER > 0x1000ffffL ECDSA_SIG_get0(sig, &sig_r, &sig_s); #else sig_r = sig->r; sig_s = sig->s; #endif int nBitsR = BN_num_bits(sig_r); int nBitsS = BN_num_bits(sig_s); if (nBitsR <= 256 && nBitsS <= 256) { int nRecId = -1; for (int i=0; i<4; i++) { CKey keyRec; keyRec.fSet = true; if (fCompressedPubKey) keyRec.SetCompressedPubKey(); if (ECDSA_SIG_recover_key_GFp(keyRec.pkey, sig, (unsigned char*)&hash, sizeof(hash), i, 1) == 1) if (keyRec.GetPubKey() == this->GetPubKey()) { nRecId = i; break; } } if (nRecId == -1) { ECDSA_SIG_free(sig); throw key_error("CKey::SignCompact() : unable to construct recoverable key"); } vchSig[0] = nRecId+27+(fCompressedPubKey ? 4 : 0); BN_bn2bin(sig_r,&vchSig[33-(nBitsR+7)/8]); BN_bn2bin(sig_s,&vchSig[65-(nBitsS+7)/8]); fOk = true; } ECDSA_SIG_free(sig); return fOk; }
void getSigRaw(ecc_signature_t *sigraw, char *inFile) { ECDSA_SIG* signature; int fdin; struct stat s; void *infile; unsigned char outbuf[2*EC_COORDBYTES]; int r, rlen, roff, slen, soff; const BIGNUM *sr, *ss; fdin = open(inFile, O_RDONLY); assert(fdin > 0); r = fstat(fdin, &s); assert(r==0); infile = mmap(NULL, s.st_size, PROT_READ, MAP_PRIVATE, fdin, 0); assert(infile); signature = d2i_ECDSA_SIG(NULL, (const unsigned char **) &infile, 7 + 2*EC_COORDBYTES); memset(&outbuf, 0, sizeof(outbuf)); #if OPENSSL_VERSION_NUMBER >= 0x10100000L ECDSA_SIG_get0(signature, &sr, &ss); #else sr = signature->r; ss = signature->s; #endif rlen = BN_num_bytes(sr); roff = 66 - rlen; BN_bn2bin(sr, &outbuf[roff]); slen = BN_num_bytes(ss); soff = 66 + (66 - slen); BN_bn2bin(sr, &outbuf[soff]); if (debug) printBytes((char *)"sig (RAW) = ", outbuf, sizeof(outbuf), 32); memcpy(*sigraw, outbuf, 2*EC_COORDBYTES); ECDSA_SIG_free(signature); close(fdin); return; }
EcdsaSignature BackendOpenSsl::sign_data(const ecdsa256::PrivateKey& key, const ByteBuffer& data) { auto priv_key = internal_private_key(key); auto digest = calculate_digest(data); // sign message data represented by the digest openssl::Signature signature { ECDSA_do_sign(digest.data(), digest.size(), priv_key) }; #if OPENSSL_API_COMPAT < 0x10100000L const BIGNUM* sig_r = signature->r; const BIGNUM* sig_s = signature->s; #else const BIGNUM* sig_r = nullptr; const BIGNUM* sig_s = nullptr; ECDSA_SIG_get0(signature, &sig_r, &sig_s); #endif EcdsaSignature ecdsa_signature; X_Coordinate_Only coordinate; if (sig_r && sig_s) { const size_t len = field_size(PublicKeyAlgorithm::ECDSA_NISTP256_With_SHA256); const auto num_bytes_s = BN_num_bytes(sig_s); assert(len >= static_cast<size_t>(num_bytes_s)); ecdsa_signature.s.resize(len, 0x00); BN_bn2bin(sig_s, ecdsa_signature.s.data() + len - num_bytes_s); const auto num_bytes_r = BN_num_bytes(sig_r); assert(len >= static_cast<size_t>(num_bytes_r)); coordinate.x.resize(len, 0x00); BN_bn2bin(sig_r, coordinate.x.data() + len - num_bytes_r); } else { throw openssl::Exception(); } ecdsa_signature.R = std::move(coordinate); return ecdsa_signature; }
BUF_MEM * convert_to_plain_sig(const BUF_MEM *x962_sig) { size_t r_len, s_len, rs_max; BUF_MEM *plain_sig_buf = NULL; ECDSA_SIG *tmp_sig = NULL; const unsigned char *tmp; unsigned char *r = NULL, *s = NULL; const BIGNUM *bn_r, *bn_s; check_return(x962_sig, "Invalid arguments"); /* Convert the ASN.1 data to a C structure*/ tmp = (unsigned char*) x962_sig->data; tmp_sig = ECDSA_SIG_new(); if (!tmp_sig) goto err; if (!d2i_ECDSA_SIG(&tmp_sig, &tmp, x962_sig->length)) goto err; ECDSA_SIG_get0(tmp_sig, &bn_r, &bn_s); /* Extract the parameters r and s*/ r_len = BN_num_bytes(bn_r); s_len = BN_num_bytes(bn_s); rs_max = r_len > s_len ? r_len : s_len; r = OPENSSL_malloc(rs_max); s = OPENSSL_malloc(rs_max); if (!r || !s) goto err; /* Convert r and s to a binary representation */ if (!BN_bn2bin(bn_r, r + rs_max - r_len)) goto err; if (!BN_bn2bin(bn_s, s + rs_max - s_len)) goto err; /* r and s must be padded with leading zero bytes to ensure they have the * same length */ memset(r, 0, rs_max - r_len); memset(s, 0, rs_max - s_len); /* concatenate r and s to get the plain signature format */ plain_sig_buf = BUF_MEM_create(rs_max + rs_max); if (!plain_sig_buf) goto err; memcpy(plain_sig_buf->data, r, rs_max); memcpy(plain_sig_buf->data + rs_max, s, rs_max); OPENSSL_free(r); OPENSSL_free(s); ECDSA_SIG_free(tmp_sig); return plain_sig_buf; err: if (r) OPENSSL_free(r); if (s) OPENSSL_free(s); if (tmp_sig) ECDSA_SIG_free(tmp_sig); return NULL; }
// Perform ECDSA key recovery (see SEC1 4.1.6) for curves over (mod p)-fields // recid selects which key is recovered // if check is non-zero, additional checks are performed int ECDSA_SIG_recover_key_GFp(EC_KEY *eckey, ECDSA_SIG *ecsig, const unsigned char *msg, int msglen, int recid, int check) { if (!eckey) return 0; const BIGNUM *sig_r, *sig_s; #if OPENSSL_VERSION_NUMBER > 0x1000ffffL ECDSA_SIG_get0(ecsig, &sig_r, &sig_s); #else sig_r = ecsig->r; sig_s = ecsig->s; #endif int ret = 0; BN_CTX *ctx = NULL; BIGNUM *x = NULL; BIGNUM *e = NULL; BIGNUM *order = NULL; BIGNUM *sor = NULL; BIGNUM *eor = NULL; BIGNUM *field = NULL; EC_POINT *R = NULL; EC_POINT *O = NULL; EC_POINT *Q = NULL; BIGNUM *rr = NULL; BIGNUM *zero = NULL; int n = 0; int i = recid / 2; const EC_GROUP *group = EC_KEY_get0_group(eckey); if ((ctx = BN_CTX_new()) == NULL) { ret = -1; goto err; } BN_CTX_start(ctx); order = BN_CTX_get(ctx); if (!EC_GROUP_get_order(group, order, ctx)) { ret = -2; goto err; } x = BN_CTX_get(ctx); if (!BN_copy(x, order)) { ret=-1; goto err; } if (!BN_mul_word(x, i)) { ret=-1; goto err; } if (!BN_add(x, x, sig_r)) { ret=-1; goto err; } field = BN_CTX_get(ctx); if (!EC_GROUP_get_curve_GFp(group, field, NULL, NULL, ctx)) { ret=-2; goto err; } if (BN_cmp(x, field) >= 0) { ret=0; goto err; } if ((R = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } if (!EC_POINT_set_compressed_coordinates_GFp(group, R, x, recid % 2, ctx)) { ret=0; goto err; } if (check) { if ((O = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } if (!EC_POINT_mul(group, O, NULL, R, order, ctx)) { ret=-2; goto err; } if (!EC_POINT_is_at_infinity(group, O)) { ret = 0; goto err; } } if ((Q = EC_POINT_new(group)) == NULL) { ret = -2; goto err; } n = EC_GROUP_get_degree(group); e = BN_CTX_get(ctx); if (!BN_bin2bn(msg, msglen, e)) { ret=-1; goto err; } if (8*msglen > n) BN_rshift(e, e, 8-(n & 7)); zero = BN_CTX_get(ctx); if (!BN_zero(zero)) { ret=-1; goto err; } if (!BN_mod_sub(e, zero, e, order, ctx)) { ret=-1; goto err; } rr = BN_CTX_get(ctx); if (!BN_mod_inverse(rr, sig_r, order, ctx)) { ret=-1; goto err; } sor = BN_CTX_get(ctx); if (!BN_mod_mul(sor, sig_s, rr, order, ctx)) { ret=-1; goto err; } eor = BN_CTX_get(ctx); if (!BN_mod_mul(eor, e, rr, order, ctx)) { ret=-1; goto err; } if (!EC_POINT_mul(group, Q, eor, R, sor, ctx)) { ret=-2; goto err; } if (!EC_KEY_set_public_key(eckey, Q)) { ret=-2; goto err; } ret = 1; err: if (ctx) { BN_CTX_end(ctx); BN_CTX_free(ctx); } if (R != NULL) EC_POINT_free(R); if (O != NULL) EC_POINT_free(O); if (Q != NULL) EC_POINT_free(Q); return ret; }
static bool _cjose_jws_build_sig_ec(cjose_jws_t *jws, const cjose_jwk_t *jwk, cjose_err *err) { bool retval = false; // ensure jwk is EC if (jwk->kty != CJOSE_JWK_KTY_EC) { CJOSE_ERROR(err, CJOSE_ERR_INVALID_ARG); return false; } ec_keydata *keydata = (ec_keydata *)jwk->keydata; EC_KEY *ec = keydata->key; ECDSA_SIG *ecdsa_sig = ECDSA_do_sign(jws->dig, jws->dig_len, ec); if (NULL == ecdsa_sig) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); goto _cjose_jws_build_sig_ec_cleanup; } // allocate buffer for signature switch (keydata->crv) { case CJOSE_JWK_EC_P_256: jws->sig_len = 32 * 2; break; case CJOSE_JWK_EC_P_384: jws->sig_len = 48 * 2; break; case CJOSE_JWK_EC_P_521: jws->sig_len = 66 * 2; break; case CJOSE_JWK_EC_INVALID: jws->sig_len = 0; break; } jws->sig = (uint8_t *)cjose_get_alloc()(jws->sig_len); if (NULL == jws->sig) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); goto _cjose_jws_build_sig_ec_cleanup; } memset(jws->sig, 0, jws->sig_len); const BIGNUM *pr, *ps; #if defined(CJOSE_OPENSSL_11X) ECDSA_SIG_get0(ecdsa_sig, &pr, &ps); #else pr = ecdsa_sig->r; ps = ecdsa_sig->s; #endif int rlen = BN_num_bytes(pr); int slen = BN_num_bytes(ps); BN_bn2bin(pr, jws->sig + jws->sig_len / 2 - rlen); BN_bn2bin(ps, jws->sig + jws->sig_len - slen); // base64url encode signed digest if (!cjose_base64url_encode((const uint8_t *)jws->sig, jws->sig_len, &jws->sig_b64u, &jws->sig_b64u_len, err)) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); goto _cjose_jws_build_sig_ec_cleanup; } retval = true; _cjose_jws_build_sig_ec_cleanup: if (ecdsa_sig) ECDSA_SIG_free(ecdsa_sig); return retval; }
/* ARGSUSED */ int ssh_ecdsa_sign(const struct sshkey *key, u_char **sigp, size_t *lenp, const u_char *data, size_t datalen, u_int compat) { ECDSA_SIG *sig = NULL; int hash_alg; u_char digest[SSH_DIGEST_MAX_LENGTH]; size_t len, dlen; struct sshbuf *b = NULL, *bb = NULL; int ret = SSH_ERR_INTERNAL_ERROR; if (lenp != NULL) *lenp = 0; if (sigp != NULL) *sigp = NULL; if (key == NULL || key->ecdsa == NULL || sshkey_type_plain(key->type) != KEY_ECDSA) return SSH_ERR_INVALID_ARGUMENT; if ((hash_alg = sshkey_ec_nid_to_hash_alg(key->ecdsa_nid)) == -1 || (dlen = ssh_digest_bytes(hash_alg)) == 0) return SSH_ERR_INTERNAL_ERROR; if ((ret = ssh_digest_memory(hash_alg, data, datalen, digest, sizeof(digest))) != 0) goto out; if ((sig = ECDSA_do_sign(digest, dlen, key->ecdsa)) == NULL) { ret = SSH_ERR_LIBCRYPTO_ERROR; goto out; } if ((bb = sshbuf_new()) == NULL || (b = sshbuf_new()) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } { const BIGNUM *r, *s; ECDSA_SIG_get0(sig, &r, &s); if ((ret = sshbuf_put_bignum2(bb, r)) != 0 || (ret = sshbuf_put_bignum2(bb, s)) != 0) { goto out; } } if ((ret = sshbuf_put_cstring(b, sshkey_ssh_name_plain(key))) != 0 || (ret = sshbuf_put_stringb(b, bb)) != 0) goto out; len = sshbuf_len(b); if (sigp != NULL) { if ((*sigp = malloc(len)) == NULL) { ret = SSH_ERR_ALLOC_FAIL; goto out; } memcpy(*sigp, sshbuf_ptr(b), len); } if (lenp != NULL) *lenp = len; ret = 0; out: explicit_bzero(digest, sizeof(digest)); sshbuf_free(b); sshbuf_free(bb); ECDSA_SIG_free(sig); return ret; }
/* some tests from the X9.62 draft */ int x9_62_test_internal(BIO *out, int nid, const char *r_in, const char *s_in) { int ret = 0; const char message[] = "abc"; unsigned char digest[20]; unsigned int dgst_len = 0; EVP_MD_CTX *md_ctx = EVP_MD_CTX_new(); EC_KEY *key = NULL; ECDSA_SIG *signature = NULL; BIGNUM *r = NULL, *s = NULL; BIGNUM *kinv = NULL, *rp = NULL; BIGNUM *sig_r, *sig_s; if (md_ctx == NULL) goto x962_int_err; /* get the message digest */ if (!EVP_DigestInit(md_ctx, EVP_sha1()) || !EVP_DigestUpdate(md_ctx, (const void *)message, 3) || !EVP_DigestFinal(md_ctx, digest, &dgst_len)) goto x962_int_err; BIO_printf(out, "testing %s: ", OBJ_nid2sn(nid)); /* create the key */ if ((key = EC_KEY_new_by_curve_name(nid)) == NULL) goto x962_int_err; use_fake = 1; if (!EC_KEY_generate_key(key)) goto x962_int_err; BIO_printf(out, "."); (void)BIO_flush(out); /* create the signature */ use_fake = 1; /* Use ECDSA_sign_setup to avoid use of ECDSA nonces */ if (!ECDSA_sign_setup(key, NULL, &kinv, &rp)) goto x962_int_err; signature = ECDSA_do_sign_ex(digest, 20, kinv, rp, key); if (signature == NULL) goto x962_int_err; BIO_printf(out, "."); (void)BIO_flush(out); /* compare the created signature with the expected signature */ if ((r = BN_new()) == NULL || (s = BN_new()) == NULL) goto x962_int_err; if (!BN_dec2bn(&r, r_in) || !BN_dec2bn(&s, s_in)) goto x962_int_err; ECDSA_SIG_get0(&sig_r, &sig_s, signature); if (BN_cmp(sig_r, r) || BN_cmp(sig_s, s)) goto x962_int_err; BIO_printf(out, "."); (void)BIO_flush(out); /* verify the signature */ if (ECDSA_do_verify(digest, 20, signature, key) != 1) goto x962_int_err; BIO_printf(out, "."); (void)BIO_flush(out); BIO_printf(out, " ok\n"); ret = 1; x962_int_err: if (!ret) BIO_printf(out, " failed\n"); EC_KEY_free(key); ECDSA_SIG_free(signature); BN_free(r); BN_free(s); EVP_MD_CTX_free(md_ctx); BN_clear_free(kinv); BN_clear_free(rp); return ret; }
/*- * This function hijacks the RNG to feed it the chosen ECDSA key and nonce. * The ECDSA KATs are from: * - the X9.62 draft (4) * - NIST CAVP (720) * * It uses the low-level ECDSA_sign_setup instead of EVP to control the RNG. * NB: This is not how applications should use ECDSA; this is only for testing. * * Tests the library can successfully: * - generate public keys that matches those KATs * - create ECDSA signatures that match those KATs * - accept those signatures as valid */ static int x9_62_tests(int n) { int nid, md_nid, ret = 0; const char *r_in = NULL, *s_in = NULL, *tbs = NULL; unsigned char *pbuf = NULL, *qbuf = NULL, *message = NULL; unsigned char digest[EVP_MAX_MD_SIZE]; unsigned int dgst_len = 0; long q_len, msg_len = 0; size_t p_len; EVP_MD_CTX *mctx = NULL; EC_KEY *key = NULL; ECDSA_SIG *signature = NULL; BIGNUM *r = NULL, *s = NULL; BIGNUM *kinv = NULL, *rp = NULL; const BIGNUM *sig_r = NULL, *sig_s = NULL; nid = ecdsa_cavs_kats[n].nid; md_nid = ecdsa_cavs_kats[n].md_nid; r_in = ecdsa_cavs_kats[n].r; s_in = ecdsa_cavs_kats[n].s; tbs = ecdsa_cavs_kats[n].msg; numbers[0] = ecdsa_cavs_kats[n].d; numbers[1] = ecdsa_cavs_kats[n].k; TEST_info("ECDSA KATs for curve %s", OBJ_nid2sn(nid)); if (!TEST_ptr(mctx = EVP_MD_CTX_new()) /* get the message digest */ || !TEST_ptr(message = OPENSSL_hexstr2buf(tbs, &msg_len)) || !TEST_true(EVP_DigestInit_ex(mctx, EVP_get_digestbynid(md_nid), NULL)) || !TEST_true(EVP_DigestUpdate(mctx, message, msg_len)) || !TEST_true(EVP_DigestFinal_ex(mctx, digest, &dgst_len)) /* create the key */ || !TEST_ptr(key = EC_KEY_new_by_curve_name(nid)) /* load KAT variables */ || !TEST_ptr(r = BN_new()) || !TEST_ptr(s = BN_new()) || !TEST_true(BN_hex2bn(&r, r_in)) || !TEST_true(BN_hex2bn(&s, s_in)) /* swap the RNG source */ || !TEST_true(change_rand())) goto err; /* public key must match KAT */ use_fake = 1; if (!TEST_true(EC_KEY_generate_key(key)) || !TEST_true(p_len = EC_KEY_key2buf(key, POINT_CONVERSION_UNCOMPRESSED, &pbuf, NULL)) || !TEST_ptr(qbuf = OPENSSL_hexstr2buf(ecdsa_cavs_kats[n].Q, &q_len)) || !TEST_int_eq(q_len, p_len) || !TEST_mem_eq(qbuf, q_len, pbuf, p_len)) goto err; /* create the signature via ECDSA_sign_setup to avoid use of ECDSA nonces */ use_fake = 1; if (!TEST_true(ECDSA_sign_setup(key, NULL, &kinv, &rp)) || !TEST_ptr(signature = ECDSA_do_sign_ex(digest, dgst_len, kinv, rp, key)) /* verify the signature */ || !TEST_int_eq(ECDSA_do_verify(digest, dgst_len, signature, key), 1)) goto err; /* compare the created signature with the expected signature */ ECDSA_SIG_get0(signature, &sig_r, &sig_s); if (!TEST_BN_eq(sig_r, r) || !TEST_BN_eq(sig_s, s)) goto err; ret = 1; err: /* restore the RNG source */ if (!TEST_true(restore_rand())) ret = 0; OPENSSL_free(message); OPENSSL_free(pbuf); OPENSSL_free(qbuf); EC_KEY_free(key); ECDSA_SIG_free(signature); BN_free(r); BN_free(s); EVP_MD_CTX_free(mctx); BN_clear_free(kinv); BN_clear_free(rp); return ret; }
/* some tests from the X9.62 draft */ static int x9_62_test_internal(int nid, const char *r_in, const char *s_in) { int ret = 0; const char message[] = "abc"; unsigned char digest[20]; unsigned int dgst_len = 0; EVP_MD_CTX *md_ctx; EC_KEY *key = NULL; ECDSA_SIG *signature = NULL; BIGNUM *r = NULL, *s = NULL; BIGNUM *kinv = NULL, *rp = NULL; const BIGNUM *sig_r, *sig_s; if (!TEST_ptr(md_ctx = EVP_MD_CTX_new())) goto x962_int_err; /* get the message digest */ if (!TEST_true(EVP_DigestInit(md_ctx, EVP_sha1())) || !TEST_true(EVP_DigestUpdate(md_ctx, (const void *)message, 3)) || !TEST_true(EVP_DigestFinal(md_ctx, digest, &dgst_len))) goto x962_int_err; TEST_info("testing %s", OBJ_nid2sn(nid)); /* create the key */ if (!TEST_ptr(key = EC_KEY_new_by_curve_name(nid))) goto x962_int_err; use_fake = 1; if (!TEST_true(EC_KEY_generate_key(key))) goto x962_int_err; /* create the signature */ use_fake = 1; /* Use ECDSA_sign_setup to avoid use of ECDSA nonces */ if (!TEST_true(ECDSA_sign_setup(key, NULL, &kinv, &rp))) goto x962_int_err; if (!TEST_ptr(signature = ECDSA_do_sign_ex(digest, 20, kinv, rp, key))) goto x962_int_err; /* compare the created signature with the expected signature */ if (!TEST_ptr(r = BN_new()) || !TEST_ptr(s = BN_new())) goto x962_int_err; if (!TEST_true(BN_dec2bn(&r, r_in)) || !TEST_true(BN_dec2bn(&s, s_in))) goto x962_int_err; ECDSA_SIG_get0(signature, &sig_r, &sig_s); if (!TEST_BN_eq(sig_r, r) || !TEST_BN_eq(sig_s, s)) goto x962_int_err; /* verify the signature */ if (!TEST_int_eq(ECDSA_do_verify(digest, 20, signature, key), 1)) goto x962_int_err; ret = 1; x962_int_err: EC_KEY_free(key); ECDSA_SIG_free(signature); BN_free(r); BN_free(s); EVP_MD_CTX_free(md_ctx); BN_clear_free(kinv); BN_clear_free(rp); return ret; }
int test_builtin(BIO *out) { EC_builtin_curve *curves = NULL; size_t crv_len = 0, n = 0; EC_KEY *eckey = NULL, *wrong_eckey = NULL; EC_GROUP *group; ECDSA_SIG *ecdsa_sig = NULL; unsigned char digest[20], wrong_digest[20]; unsigned char *signature = NULL; const unsigned char *sig_ptr; unsigned char *sig_ptr2; unsigned char *raw_buf = NULL; BIGNUM *sig_r, *sig_s; unsigned int sig_len, degree, r_len, s_len, bn_len, buf_len; int nid, ret = 0; /* fill digest values with some random data */ if (RAND_bytes(digest, 20) <= 0 || RAND_bytes(wrong_digest, 20) <= 0) { BIO_printf(out, "ERROR: unable to get random data\n"); goto builtin_err; } /* * create and verify a ecdsa signature with every availble curve (with ) */ BIO_printf(out, "\ntesting ECDSA_sign() and ECDSA_verify() " "with some internal curves:\n"); /* get a list of all internal curves */ crv_len = EC_get_builtin_curves(NULL, 0); curves = OPENSSL_malloc(sizeof(*curves) * crv_len); if (curves == NULL) { BIO_printf(out, "malloc error\n"); goto builtin_err; } if (!EC_get_builtin_curves(curves, crv_len)) { BIO_printf(out, "unable to get internal curves\n"); goto builtin_err; } /* now create and verify a signature for every curve */ for (n = 0; n < crv_len; n++) { unsigned char dirt, offset; nid = curves[n].nid; if (nid == NID_ipsec4 || nid == NID_X25519) continue; /* create new ecdsa key (== EC_KEY) */ if ((eckey = EC_KEY_new()) == NULL) goto builtin_err; group = EC_GROUP_new_by_curve_name(nid); if (group == NULL) goto builtin_err; if (EC_KEY_set_group(eckey, group) == 0) goto builtin_err; EC_GROUP_free(group); degree = EC_GROUP_get_degree(EC_KEY_get0_group(eckey)); if (degree < 160) { /* drop the curve */ EC_KEY_free(eckey); eckey = NULL; continue; } BIO_printf(out, "%s: ", OBJ_nid2sn(nid)); /* create key */ if (!EC_KEY_generate_key(eckey)) { BIO_printf(out, " failed\n"); goto builtin_err; } /* create second key */ if ((wrong_eckey = EC_KEY_new()) == NULL) goto builtin_err; group = EC_GROUP_new_by_curve_name(nid); if (group == NULL) goto builtin_err; if (EC_KEY_set_group(wrong_eckey, group) == 0) goto builtin_err; EC_GROUP_free(group); if (!EC_KEY_generate_key(wrong_eckey)) { BIO_printf(out, " failed\n"); goto builtin_err; } BIO_printf(out, "."); (void)BIO_flush(out); /* check key */ if (!EC_KEY_check_key(eckey)) { BIO_printf(out, " failed\n"); goto builtin_err; } BIO_printf(out, "."); (void)BIO_flush(out); /* create signature */ sig_len = ECDSA_size(eckey); if ((signature = OPENSSL_malloc(sig_len)) == NULL) goto builtin_err; if (!ECDSA_sign(0, digest, 20, signature, &sig_len, eckey)) { BIO_printf(out, " failed\n"); goto builtin_err; } BIO_printf(out, "."); (void)BIO_flush(out); /* verify signature */ if (ECDSA_verify(0, digest, 20, signature, sig_len, eckey) != 1) { BIO_printf(out, " failed\n"); goto builtin_err; } BIO_printf(out, "."); (void)BIO_flush(out); /* verify signature with the wrong key */ if (ECDSA_verify(0, digest, 20, signature, sig_len, wrong_eckey) == 1) { BIO_printf(out, " failed\n"); goto builtin_err; } BIO_printf(out, "."); (void)BIO_flush(out); /* wrong digest */ if (ECDSA_verify(0, wrong_digest, 20, signature, sig_len, eckey) == 1) { BIO_printf(out, " failed\n"); goto builtin_err; } BIO_printf(out, "."); (void)BIO_flush(out); /* wrong length */ if (ECDSA_verify(0, digest, 20, signature, sig_len - 1, eckey) == 1) { BIO_printf(out, " failed\n"); goto builtin_err; } BIO_printf(out, "."); (void)BIO_flush(out); /* * Modify a single byte of the signature: to ensure we don't garble * the ASN1 structure, we read the raw signature and modify a byte in * one of the bignums directly. */ sig_ptr = signature; if ((ecdsa_sig = d2i_ECDSA_SIG(NULL, &sig_ptr, sig_len)) == NULL) { BIO_printf(out, " failed\n"); goto builtin_err; } ECDSA_SIG_get0(&sig_r, &sig_s, ecdsa_sig); /* Store the two BIGNUMs in raw_buf. */ r_len = BN_num_bytes(sig_r); s_len = BN_num_bytes(sig_s); bn_len = (degree + 7) / 8; if ((r_len > bn_len) || (s_len > bn_len)) { BIO_printf(out, " failed\n"); goto builtin_err; } buf_len = 2 * bn_len; if ((raw_buf = OPENSSL_zalloc(buf_len)) == NULL) goto builtin_err; BN_bn2bin(sig_r, raw_buf + bn_len - r_len); BN_bn2bin(sig_s, raw_buf + buf_len - s_len); /* Modify a single byte in the buffer. */ offset = raw_buf[10] % buf_len; dirt = raw_buf[11] ? raw_buf[11] : 1; raw_buf[offset] ^= dirt; /* Now read the BIGNUMs back in from raw_buf. */ if ((BN_bin2bn(raw_buf, bn_len, sig_r) == NULL) || (BN_bin2bn(raw_buf + bn_len, bn_len, sig_s) == NULL)) goto builtin_err; sig_ptr2 = signature; sig_len = i2d_ECDSA_SIG(ecdsa_sig, &sig_ptr2); if (ECDSA_verify(0, digest, 20, signature, sig_len, eckey) == 1) { BIO_printf(out, " failed\n"); goto builtin_err; } /* * Sanity check: undo the modification and verify signature. */ raw_buf[offset] ^= dirt; if ((BN_bin2bn(raw_buf, bn_len, sig_r) == NULL) || (BN_bin2bn(raw_buf + bn_len, bn_len, sig_s) == NULL)) goto builtin_err; sig_ptr2 = signature; sig_len = i2d_ECDSA_SIG(ecdsa_sig, &sig_ptr2); if (ECDSA_verify(0, digest, 20, signature, sig_len, eckey) != 1) { BIO_printf(out, " failed\n"); goto builtin_err; } BIO_printf(out, "."); (void)BIO_flush(out); BIO_printf(out, " ok\n"); /* cleanup */ /* clean bogus errors */ ERR_clear_error(); OPENSSL_free(signature); signature = NULL; EC_KEY_free(eckey); eckey = NULL; EC_KEY_free(wrong_eckey); wrong_eckey = NULL; ECDSA_SIG_free(ecdsa_sig); ecdsa_sig = NULL; OPENSSL_free(raw_buf); raw_buf = NULL; } ret = 1; builtin_err: EC_KEY_free(eckey); EC_KEY_free(wrong_eckey); ECDSA_SIG_free(ecdsa_sig); OPENSSL_free(signature); OPENSSL_free(raw_buf); OPENSSL_free(curves); return ret; }
static int test_builtin(void) { EC_builtin_curve *curves = NULL; size_t crv_len = 0, n = 0; EC_KEY *eckey = NULL, *wrong_eckey = NULL; EC_GROUP *group; ECDSA_SIG *ecdsa_sig = NULL, *modified_sig = NULL; unsigned char digest[20], wrong_digest[20]; unsigned char *signature = NULL; const unsigned char *sig_ptr; unsigned char *sig_ptr2; unsigned char *raw_buf = NULL; const BIGNUM *sig_r, *sig_s; BIGNUM *modified_r = NULL, *modified_s = NULL; BIGNUM *unmodified_r = NULL, *unmodified_s = NULL; unsigned int sig_len, degree, r_len, s_len, bn_len, buf_len; int nid, ret = 0; /* fill digest values with some random data */ if (!TEST_true(RAND_bytes(digest, 20)) || !TEST_true(RAND_bytes(wrong_digest, 20))) goto builtin_err; /* create and verify a ecdsa signature with every available curve */ /* get a list of all internal curves */ crv_len = EC_get_builtin_curves(NULL, 0); if (!TEST_ptr(curves = OPENSSL_malloc(sizeof(*curves) * crv_len)) || !TEST_true(EC_get_builtin_curves(curves, crv_len))) goto builtin_err; /* now create and verify a signature for every curve */ for (n = 0; n < crv_len; n++) { unsigned char dirt, offset; nid = curves[n].nid; if (nid == NID_ipsec4 || nid == NID_X25519) continue; /* create new ecdsa key (== EC_KEY) */ if (!TEST_ptr(eckey = EC_KEY_new()) || !TEST_ptr(group = EC_GROUP_new_by_curve_name(nid)) || !TEST_true(EC_KEY_set_group(eckey, group))) goto builtin_err; EC_GROUP_free(group); degree = EC_GROUP_get_degree(EC_KEY_get0_group(eckey)); if (degree < 160) { /* drop the curve */ EC_KEY_free(eckey); eckey = NULL; continue; } TEST_info("testing %s", OBJ_nid2sn(nid)); /* create key */ if (!TEST_true(EC_KEY_generate_key(eckey))) goto builtin_err; /* create second key */ if (!TEST_ptr(wrong_eckey = EC_KEY_new()) || !TEST_ptr(group = EC_GROUP_new_by_curve_name(nid)) || !TEST_true(EC_KEY_set_group(wrong_eckey, group))) goto builtin_err; EC_GROUP_free(group); if (!TEST_true(EC_KEY_generate_key(wrong_eckey))) goto builtin_err; /* check key */ if (!TEST_true(EC_KEY_check_key(eckey))) goto builtin_err; /* create signature */ sig_len = ECDSA_size(eckey); if (!TEST_ptr(signature = OPENSSL_malloc(sig_len)) || !TEST_true(ECDSA_sign(0, digest, 20, signature, &sig_len, eckey))) goto builtin_err; /* verify signature */ if (!TEST_int_eq(ECDSA_verify(0, digest, 20, signature, sig_len, eckey), 1)) goto builtin_err; /* verify signature with the wrong key */ if (!TEST_int_ne(ECDSA_verify(0, digest, 20, signature, sig_len, wrong_eckey), 1)) goto builtin_err; /* wrong digest */ if (!TEST_int_ne(ECDSA_verify(0, wrong_digest, 20, signature, sig_len, eckey), 1)) goto builtin_err; /* wrong length */ if (!TEST_int_ne(ECDSA_verify(0, digest, 20, signature, sig_len - 1, eckey), 1)) goto builtin_err; /* * Modify a single byte of the signature: to ensure we don't garble * the ASN1 structure, we read the raw signature and modify a byte in * one of the bignums directly. */ sig_ptr = signature; if (!TEST_ptr(ecdsa_sig = d2i_ECDSA_SIG(NULL, &sig_ptr, sig_len))) goto builtin_err; ECDSA_SIG_get0(ecdsa_sig, &sig_r, &sig_s); /* Store the two BIGNUMs in raw_buf. */ r_len = BN_num_bytes(sig_r); s_len = BN_num_bytes(sig_s); bn_len = (degree + 7) / 8; if (!TEST_false(r_len > bn_len) || !TEST_false(s_len > bn_len)) goto builtin_err; buf_len = 2 * bn_len; if (!TEST_ptr(raw_buf = OPENSSL_zalloc(buf_len))) goto builtin_err; BN_bn2bin(sig_r, raw_buf + bn_len - r_len); BN_bn2bin(sig_s, raw_buf + buf_len - s_len); /* Modify a single byte in the buffer. */ offset = raw_buf[10] % buf_len; dirt = raw_buf[11] ? raw_buf[11] : 1; raw_buf[offset] ^= dirt; /* Now read the BIGNUMs back in from raw_buf. */ if (!TEST_ptr(modified_sig = ECDSA_SIG_new())) goto builtin_err; if (!TEST_ptr(modified_r = BN_bin2bn(raw_buf, bn_len, NULL)) || !TEST_ptr(modified_s = BN_bin2bn(raw_buf + bn_len, bn_len, NULL)) || !TEST_true(ECDSA_SIG_set0(modified_sig, modified_r, modified_s))) { BN_free(modified_r); BN_free(modified_s); goto builtin_err; } sig_ptr2 = signature; sig_len = i2d_ECDSA_SIG(modified_sig, &sig_ptr2); if (!TEST_false(ECDSA_verify(0, digest, 20, signature, sig_len, eckey))) goto builtin_err; /* Sanity check: undo the modification and verify signature. */ raw_buf[offset] ^= dirt; if (!TEST_ptr(unmodified_r = BN_bin2bn(raw_buf, bn_len, NULL)) || !TEST_ptr(unmodified_s = BN_bin2bn(raw_buf + bn_len, bn_len, NULL)) || !TEST_true(ECDSA_SIG_set0(modified_sig, unmodified_r, unmodified_s))) { BN_free(unmodified_r); BN_free(unmodified_s); goto builtin_err; } sig_ptr2 = signature; sig_len = i2d_ECDSA_SIG(modified_sig, &sig_ptr2); if (!TEST_true(ECDSA_verify(0, digest, 20, signature, sig_len, eckey))) goto builtin_err; /* cleanup */ ERR_clear_error(); OPENSSL_free(signature); signature = NULL; EC_KEY_free(eckey); eckey = NULL; EC_KEY_free(wrong_eckey); wrong_eckey = NULL; ECDSA_SIG_free(ecdsa_sig); ecdsa_sig = NULL; ECDSA_SIG_free(modified_sig); modified_sig = NULL; OPENSSL_free(raw_buf); raw_buf = NULL; } ret = 1; builtin_err: EC_KEY_free(eckey); EC_KEY_free(wrong_eckey); ECDSA_SIG_free(ecdsa_sig); ECDSA_SIG_free(modified_sig); OPENSSL_free(signature); OPENSSL_free(raw_buf); OPENSSL_free(curves); return ret; }
int jwt_sign_sha_pem(jwt_t *jwt, char **out, unsigned int *len, const char *str) { EVP_MD_CTX *mdctx = NULL; ECDSA_SIG *ec_sig = NULL; const BIGNUM *ec_sig_r = NULL; const BIGNUM *ec_sig_s = NULL; BIO *bufkey = NULL; const EVP_MD *alg; int type; EVP_PKEY *pkey = NULL; int pkey_type; unsigned char *sig; int ret = 0; size_t slen; switch (jwt->alg) { /* RSA */ case JWT_ALG_RS256: alg = EVP_sha256(); type = EVP_PKEY_RSA; break; case JWT_ALG_RS384: alg = EVP_sha384(); type = EVP_PKEY_RSA; break; case JWT_ALG_RS512: alg = EVP_sha512(); type = EVP_PKEY_RSA; break; /* ECC */ case JWT_ALG_ES256: alg = EVP_sha256(); type = EVP_PKEY_EC; break; case JWT_ALG_ES384: alg = EVP_sha384(); type = EVP_PKEY_EC; break; case JWT_ALG_ES512: alg = EVP_sha512(); type = EVP_PKEY_EC; break; default: return EINVAL; } bufkey = BIO_new_mem_buf(jwt->key, jwt->key_len); if (bufkey == NULL) SIGN_ERROR(ENOMEM); /* This uses OpenSSL's default passphrase callback if needed. The * library caller can override this in many ways, all of which are * outside of the scope of LibJWT and this is documented in jwt.h. */ pkey = PEM_read_bio_PrivateKey(bufkey, NULL, NULL, NULL); if (pkey == NULL) SIGN_ERROR(EINVAL); pkey_type = EVP_PKEY_id(pkey); if (pkey_type != type) SIGN_ERROR(EINVAL); mdctx = EVP_MD_CTX_create(); if (mdctx == NULL) SIGN_ERROR(ENOMEM); /* Initialize the DigestSign operation using alg */ if (EVP_DigestSignInit(mdctx, NULL, alg, NULL, pkey) != 1) SIGN_ERROR(EINVAL); /* Call update with the message */ if (EVP_DigestSignUpdate(mdctx, str, strlen(str)) != 1) SIGN_ERROR(EINVAL); /* First, call EVP_DigestSignFinal with a NULL sig parameter to get length * of sig. Length is returned in slen */ if (EVP_DigestSignFinal(mdctx, NULL, &slen) != 1) SIGN_ERROR(EINVAL); /* Allocate memory for signature based on returned size */ sig = alloca(slen); if (sig == NULL) SIGN_ERROR(ENOMEM); /* Get the signature */ if (EVP_DigestSignFinal(mdctx, sig, &slen) != 1) SIGN_ERROR(EINVAL); if (pkey_type != EVP_PKEY_EC) { *out = malloc(slen); if (*out == NULL) SIGN_ERROR(ENOMEM); memcpy(*out, sig, slen); *len = slen; } else { unsigned int degree, bn_len, r_len, s_len, buf_len; unsigned char *raw_buf; EC_KEY *ec_key; /* For EC we need to convert to a raw format of R/S. */ /* Get the actual ec_key */ ec_key = EVP_PKEY_get1_EC_KEY(pkey); if (ec_key == NULL) SIGN_ERROR(ENOMEM); degree = EC_GROUP_get_degree(EC_KEY_get0_group(ec_key)); EC_KEY_free(ec_key); /* Get the sig from the DER encoded version. */ ec_sig = d2i_ECDSA_SIG(NULL, (const unsigned char **)&sig, slen); if (ec_sig == NULL) SIGN_ERROR(ENOMEM); ECDSA_SIG_get0(ec_sig, &ec_sig_r, &ec_sig_s); r_len = BN_num_bytes(ec_sig_r); s_len = BN_num_bytes(ec_sig_s); bn_len = (degree + 7) / 8; if ((r_len > bn_len) || (s_len > bn_len)) SIGN_ERROR(EINVAL); buf_len = 2 * bn_len; raw_buf = alloca(buf_len); if (raw_buf == NULL) SIGN_ERROR(ENOMEM); /* Pad the bignums with leading zeroes. */ memset(raw_buf, 0, buf_len); BN_bn2bin(ec_sig_r, raw_buf + bn_len - r_len); BN_bn2bin(ec_sig_s, raw_buf + buf_len - s_len); *out = malloc(buf_len); if (*out == NULL) SIGN_ERROR(ENOMEM); memcpy(*out, raw_buf, buf_len); *len = buf_len; } jwt_sign_sha_pem_done: if (bufkey) BIO_free(bufkey); if (pkey) EVP_PKEY_free(pkey); if (mdctx) EVP_MD_CTX_destroy(mdctx); if (ec_sig) ECDSA_SIG_free(ec_sig); return ret; }