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; 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_pseudo_bytes(digest, 20) || !RAND_pseudo_bytes(wrong_digest, 20)) { 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(EC_builtin_curve) * 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) 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; } /* Store the two BIGNUMs in raw_buf. */ r_len = BN_num_bytes(ecdsa_sig->r); s_len = BN_num_bytes(ecdsa_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_malloc(buf_len)) == NULL) goto builtin_err; /* Pad the bignums with leading zeroes. */ memset(raw_buf, 0, buf_len); BN_bn2bin(ecdsa_sig->r, raw_buf + bn_len - r_len); BN_bn2bin(ecdsa_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, ecdsa_sig->r) == NULL) || (BN_bin2bn(raw_buf + bn_len, bn_len, ecdsa_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, ecdsa_sig->r) == NULL) || (BN_bin2bn(raw_buf + bn_len, bn_len, ecdsa_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: if (eckey) EC_KEY_free(eckey); if (wrong_eckey) EC_KEY_free(wrong_eckey); if (ecdsa_sig) ECDSA_SIG_free(ecdsa_sig); if (signature) OPENSSL_free(signature); if (raw_buf) OPENSSL_free(raw_buf); if (curves) OPENSSL_free(curves); return ret; }
bool CKey::Verify(uint256 hash, const std::vector<unsigned char>& vchSig) { if (vchSig.empty()) return false; // New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first. unsigned char *norm_der = NULL; ECDSA_SIG *norm_sig = ECDSA_SIG_new(); const unsigned char* sigptr = &vchSig[0]; assert(norm_sig); if (d2i_ECDSA_SIG(&norm_sig, &sigptr, vchSig.size()) == NULL) { /* As of OpenSSL 1.0.0p d2i_ECDSA_SIG frees and nulls the pointer on * error. But OpenSSL's own use of this function redundantly frees the * result. As ECDSA_SIG_free(NULL) is a no-op, and in the absence of a * clear contract for the function behaving the same way is more * conservative. */ ECDSA_SIG_free(norm_sig); return false; } int derlen = i2d_ECDSA_SIG(norm_sig, &norm_der); ECDSA_SIG_free(norm_sig); if (derlen <= 0) return false; // -1 = error, 0 = bad sig, 1 = good bool ret = ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), norm_der, derlen, pkey) == 1; OPENSSL_free(norm_der); return ret; }
/* returns * 1: correct signature * 0: incorrect signature * -1: error */ int ECDSA_verify(int type, const unsigned char *dgst, int dgst_len, const unsigned char *sigbuf, int sig_len, EC_KEY *eckey) { ECDSA_SIG *s; unsigned char *der = NULL; const unsigned char *p = sigbuf; int derlen = -1; int ret = -1; s = ECDSA_SIG_new(); if (s == NULL) return (ret); if (d2i_ECDSA_SIG(&s, &p, sig_len) == NULL) goto err; /* Ensure signature uses DER and doesn't have trailing garbage */ derlen = i2d_ECDSA_SIG(s, &der); if (derlen != sig_len || memcmp(sigbuf, der, derlen)) goto err; ret = ECDSA_do_verify(dgst, dgst_len, s, eckey); err: freezero(der, derlen); ECDSA_SIG_free(s); return (ret); }
bool CKey::ReserealizeSignature(std::vector<unsigned char>& vchSig) { unsigned char *pos; if (vchSig.empty()) return false; pos = &vchSig[0]; ECDSA_SIG *sig = d2i_ECDSA_SIG(NULL, (const unsigned char **)&pos, vchSig.size()); if (sig == NULL) return false; bool ret = false; int nSize = i2d_ECDSA_SIG(sig, NULL); if (nSize > 0) { vchSig.resize(nSize); // grow or shrink as needed pos = &vchSig[0]; i2d_ECDSA_SIG(sig, &pos); ret = true; } ECDSA_SIG_free(sig); return ret; }
u2fs_rc decode_ECDSA(const unsigned char *data, size_t len, u2fs_ECDSA_t ** sig) { const unsigned char *p; if (data == NULL || len == 0 || sig == NULL) return U2FS_MEMORY_ERROR; p = data; *sig = (u2fs_ECDSA_t *) d2i_ECDSA_SIG(NULL, &p, len); if (*sig == NULL) { if (debug) { unsigned long err = 0; err = ERR_get_error(); fprintf(stderr, "Error: %s, %s, %s\n", ERR_lib_error_string(err), ERR_func_error_string(err), ERR_reason_error_string(err)); } return U2FS_CRYPTO_ERROR; } return U2FS_OK; }
int main() { uint8_t pub_bytes[33] = { 0x02, 0x82, 0x00, 0x6e, 0x93, 0x98, 0xa6, 0x98, 0x6e, 0xda, 0x61, 0xfe, 0x91, 0x67, 0x4c, 0x3a, 0x10, 0x8c, 0x39, 0x94, 0x75, 0xbf, 0x1e, 0x73, 0x8f, 0x19, 0xdf, 0xc2, 0xdb, 0x11, 0xdb, 0x1d, 0x28 }; uint8_t der_bytes[] = { 0x30, 0x44, 0x02, 0x20, 0x2b, 0x2b, 0x52, 0x9b, 0xdb, 0xdc, 0x93, 0xe7, 0x8a, 0xf7, 0xe0, 0x02, 0x28, 0xb1, 0x79, 0x91, 0x8b, 0x03, 0x2d, 0x76, 0x90, 0x2f, 0x74, 0xef, 0x45, 0x44, 0x26, 0xf7, 0xd0, 0x6c, 0xd0, 0xf9, 0x02, 0x20, 0x62, 0xdd, 0xc7, 0x64, 0x51, 0xcd, 0x04, 0xcb, 0x56, 0x7c, 0xa5, 0xc5, 0xe0, 0x47, 0xe8, 0xac, 0x41, 0xd3, 0xd4, 0xcf, 0x7c, 0xb9, 0x24, 0x34, 0xd5, 0x5c, 0xb4, 0x86, 0xcc, 0xcf, 0x6a, 0xf2 }; const char message[] = "This is a very confidential message\n"; EC_KEY *key; const uint8_t *der_bytes_copy; ECDSA_SIG *signature; uint8_t digest[32]; int verified; key = bbp_ec_new_pubkey(pub_bytes, sizeof(pub_bytes)); if (!key) { puts("Unable to create keypair"); return -1; } der_bytes_copy = der_bytes; signature = d2i_ECDSA_SIG(NULL, &der_bytes_copy, sizeof(der_bytes)); printf("r: %s\n", BN_bn2hex(signature->r)); printf("s: %s\n", BN_bn2hex(signature->s)); bbp_sha256(digest, (uint8_t *)message, strlen(message)); bbp_print_hex("digest", digest, 32); verified = ECDSA_do_verify(digest, sizeof(digest), signature, key); switch (verified) { case 1: puts("verified"); break; case 0: puts("not verified"); break; case -1: puts("library error"); break; } ECDSA_SIG_free(signature); EC_KEY_free(key); return 0; }
/*! * \brief Finish the signing and write out the ECDSA signature. * \see rsa_sign_write */ static int ecdsa_sign_write(const knot_dnssec_sign_context_t *context, uint8_t *signature, size_t signature_size) { assert(context); assert(signature); size_t output_size = ecdsa_sign_size(context->key); if (output_size != signature_size) { return KNOT_DNSSEC_EUNEXPECTED_SIGNATURE_SIZE; } // create raw signature uint8_t *raw_signature = NULL; size_t raw_size = 0; int result = sign_alloc_and_write(context, &raw_signature, &raw_size); if (result != KNOT_EOK) { return result; } // decode signature ECDSA_SIG *decoded = ECDSA_SIG_new(); if (!decoded) { free(raw_signature); return KNOT_ENOMEM; } const uint8_t *decode_scan = raw_signature; if (!d2i_ECDSA_SIG(&decoded, &decode_scan, (long)raw_size)) { ECDSA_SIG_free(decoded); free(raw_signature); return KNOT_DNSSEC_EDECODE_RAW_SIGNATURE; } free(raw_signature); // convert to format defined by RFC 6605 (EC DSA for DNSSEC) // R and S parameters are encoded in halves of the output signature uint8_t *signature_r; uint8_t *signature_s; size_t param_size = output_size / 2; memset(signature, '\0', output_size); signature_r = signature + param_size - BN_num_bytes(decoded->r); signature_s = signature + 2 * param_size - BN_num_bytes(decoded->s); BN_bn2bin(decoded->r, signature_r); BN_bn2bin(decoded->s, signature_s); ECDSA_SIG_free(decoded); return KNOT_EOK; }
// Credit: https://github.com/ppcoin/ppcoin/pull/101/files bool CKey::Verify(uint256 hash, const std::vector<unsigned char>& vchSigParam) { // Prevent the problem described here: // https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-July/009697.html // by removing the extra length bytes std::vector<unsigned char> vchSig(vchSigParam.begin(), vchSigParam.end()); if (vchSig.size() > 1 && vchSig[1] & 0x80) { unsigned char nLengthBytes = vchSig[1] & 0x7f; if (vchSig.size() < 2 + nLengthBytes) return false; if (nLengthBytes > 4) { unsigned char nExtraBytes = nLengthBytes - 4; for (unsigned char i = 0; i < nExtraBytes; i++) if (vchSig[2 + i]) return false; vchSig.erase(vchSig.begin() + 2, vchSig.begin() + 2 + nExtraBytes); vchSig[1] = 0x80 | (nLengthBytes - nExtraBytes); } } if (vchSig.empty()) return false; // New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first. unsigned char *norm_der = NULL; ECDSA_SIG *norm_sig = ECDSA_SIG_new(); const unsigned char* sigptr = &vchSig[0]; assert(norm_sig); if (d2i_ECDSA_SIG(&norm_sig, &sigptr, vchSig.size()) == NULL) { /* As of OpenSSL 1.0.0p d2i_ECDSA_SIG frees and nulls the pointer on * error. But OpenSSL's own use of this function redundantly frees the * result. As ECDSA_SIG_free(NULL) is a no-op, and in the absence of a * clear contract for the function behaving the same way is more * conservative. */ ECDSA_SIG_free(norm_sig); return false; } int derlen = i2d_ECDSA_SIG(norm_sig, &norm_der); ECDSA_SIG_free(norm_sig); if (derlen <= 0) return false; // -1 = error, 0 = bad sig, 1 = good bool ret = ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), norm_der, derlen, pkey) == 1; OPENSSL_free(norm_der); return ret; }
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; }
/* returns * 1: correct signature * 0: incorrect signature * -1: error */ int ECDSA_verify(int type, const unsigned char *dgst, int dgst_len, const unsigned char *sigbuf, int sig_len, EC_KEY *eckey) { ECDSA_SIG *s; int ret=-1; s = ECDSA_SIG_new(); if (s == NULL) return(ret); if (d2i_ECDSA_SIG(&s, &sigbuf, sig_len) == NULL) goto err; ret=ECDSA_do_verify(dgst, dgst_len, s, eckey); err: ECDSA_SIG_free(s); return(ret); }
bool CKey::Verify(uint256 hash, const std::vector<unsigned char>& vchSigParam) { // Fix invalid signature with crafted length by removing extra length bytes std::vector<unsigned char> vchSig(vchSigParam.begin(), vchSigParam.end()); if (vchSig.size() > 1 && vchSig[1] & 0x80) { unsigned char nLengthBytes = vchSig[1] & 0x7f; if (vchSig.size() < 2 + nLengthBytes) // Avoid invalid memory access on crafted signature return false; if (nLengthBytes > 4) { unsigned char nExtraBytes = nLengthBytes - 4; for (unsigned char i = 0; i < nExtraBytes; i++) if (vchSig[2 + i]) return false; vchSig.erase(vchSig.begin() + 2, vchSig.begin() + 2 + nExtraBytes); vchSig[1] = 0x80 | (nLengthBytes - nExtraBytes); } } if (vchSig.empty()) return false; // New versions of OpenSSL will reject non-canonical DER signatures. De/re-serialize first. unsigned char *norm_der = NULL; ECDSA_SIG *norm_sig = ECDSA_SIG_new(); const unsigned char* sigptr = &vchSig[0]; assert(norm_sig); if (d2i_ECDSA_SIG(&norm_sig, &sigptr, vchSig.size()) == NULL) { /* As of OpenSSL 1.0.0p d2i_ECDSA_SIG frees and nulls the pointer on error. * But OpenSSL's own use of this function redundantly frees the result. * As ECDSA_SIG_free(NULL) is a no-op, and in the absence of a clear contract for the function behaving the same way is more conservative. */ ECDSA_SIG_free(norm_sig); return false; } int derlen = i2d_ECDSA_SIG(norm_sig, &norm_der); ECDSA_SIG_free(norm_sig); if (derlen <= 0) return false; // -1 = error, 0 = bad sig, 1 = good bool ret = ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), norm_der, derlen, pkey) == 1; OPENSSL_free(norm_der); return ret; }
bool CKey::Verify(uint256 hash, const std::vector<unsigned char>& vchSig) { // New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first. unsigned char *norm_der = NULL; ECDSA_SIG *norm_sig = ECDSA_SIG_new(); const unsigned char* sigptr = &vchSig[0]; d2i_ECDSA_SIG(&norm_sig, &sigptr, vchSig.size()); int derlen = i2d_ECDSA_SIG(norm_sig, &norm_der); ECDSA_SIG_free(norm_sig); if (derlen <= 0) return false; // -1 = error, 0 = bad sig, 1 = good bool ret = ECDSA_verify(0, (unsigned char*)&hash, sizeof(hash), norm_der, derlen, pkey) == 1; OPENSSL_free(norm_der); return ret; }
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; }
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; }
jint Java_org_keysupport_provider_ECDSASignature_jniVerifyFinal(JNIEnv *env, jobject obj, jbyteArray jmsg, jint jmdid, jbyteArray jsig) { // LOGD("entering ECDSASignature_jniVerifyFinal"); EC_Ctx *ec; EVP_MD_CTX *ctx = 0; const EVP_MD *md; jsize msgLen = 0; jsize sigLen = 0; const unsigned char *sig_ptr = NULL; if (!(ec = get_ptr(env, obj))) { LOGE("Failed to obtain key pointer"); return 0; } if (!(ctx = (EVP_MD_CTX *) malloc(sizeof(EVP_MD_CTX)))) { throw_exception(env, "java/lang/RuntimeException", "allocating EVP_MD_CTX"); destroy_ec_ctx(ec); FIPS_md_ctx_destroy(ctx); return 0; } md = FIPS_get_digestbynid(jmdid); ctx = EVP_MD_CTX_create(); msgLen = (*env)->GetArrayLength(env, jmsg); sigLen = (*env)->GetArrayLength(env, jsig); jbyte msg[msgLen]; jbyte sig[sigLen]; (*env)->GetByteArrayRegion(env, jmsg, 0, msgLen, msg); (*env)->GetByteArrayRegion(env, jsig, 0, sigLen, sig); sig_ptr = sig; ECDSA_SIG *esig = d2i_ECDSA_SIG(NULL, &sig_ptr, sigLen); FIPS_digestinit(ctx, md); int ok = FIPS_ecdsa_verify(ec->ec, msg, msgLen, md, esig); /* * This is handled a bit differently than the way OpenSSL * handles RSA Signatures, so our error handling below is a bit different. * * returns * 1: correct signature * 0: incorrect signature * -1: error */ // LOGD("FIPS_ecdsa_verify Returned: %d\n", ok); FIPS_md_ctx_destroy(ctx); FIPS_ecdsa_sig_free(esig); if (ok == 0) { throw_exception(env, "java/security/SignatureException", "Bad Signature"); return 0; } else if (ok == -1) { /* * TODO: Print any pending errors * ERR_print_errors_fp(ANDROID_LOG_ERROR); */ ERR_load_crypto_strings(); LOGE("%s", ERR_error_string(ERR_peek_error(), NULL)); throw_exception(env, "java/security/SignatureException", "jniVerifyFinal fail"); ERR_free_strings(); return 0; } // LOGD("leaving ECDSASignature_jniVerifyFinal"); return ok; }
int test_builtin(BIO *out) { size_t n = 0; EC_KEY *eckey = NULL, *wrong_eckey = NULL; EC_GROUP *group; BIGNUM *order = NULL; 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; unsigned int sig_len, r_len, s_len, bn_len, buf_len; int nid, ret = 0; /* fill digest values with some random data */ if (!RAND_pseudo_bytes(digest, 20) || !RAND_pseudo_bytes(wrong_digest, 20)) { BIO_printf(out, "ERROR: unable to get random data\n"); goto builtin_err; } order = BN_new(); if (order == NULL) { 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"); static const int kCurveNIDs[] = {NID_secp224r1, NID_X9_62_prime256v1, NID_secp384r1, NID_secp521r1, NID_undef}; /* now create and verify a signature for every curve */ for (n = 0; kCurveNIDs[n] != NID_undef; n++) { unsigned char dirt, offset; nid = kCurveNIDs[n]; /* create new ecdsa key (== EC_KEY) */ eckey = EC_KEY_new(); if (eckey == 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)) { goto builtin_err; } EC_GROUP_free(group); if (!EC_GROUP_get_order(EC_KEY_get0_group(eckey), order, NULL)) { goto builtin_err; } if (BN_num_bits(order) < 160) { /* Too small to test. */ 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 */ wrong_eckey = EC_KEY_new(); if (wrong_eckey == 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); signature = OPENSSL_malloc(sig_len); if (signature == 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; ecdsa_sig = d2i_ECDSA_SIG(NULL, &sig_ptr, sig_len); if (ecdsa_sig == NULL) { BIO_printf(out, " failed\n"); goto builtin_err; } /* Store the two BIGNUMs in raw_buf. */ r_len = BN_num_bytes(ecdsa_sig->r); s_len = BN_num_bytes(ecdsa_sig->s); bn_len = BN_num_bytes(order); if (r_len > bn_len || s_len > bn_len) { BIO_printf(out, " failed\n"); goto builtin_err; } buf_len = 2 * bn_len; raw_buf = OPENSSL_malloc(2 * bn_len); if (raw_buf == NULL) { goto builtin_err; } /* Pad the bignums with leading zeroes. */ if (!BN_bn2bin_padded(raw_buf, bn_len, ecdsa_sig->r) || !BN_bn2bin_padded(raw_buf + bn_len, bn_len, ecdsa_sig->s)) { goto builtin_err; } /* 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, ecdsa_sig->r) == NULL || BN_bin2bn(raw_buf + bn_len, bn_len, ecdsa_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, ecdsa_sig->r) == NULL || BN_bin2bn(raw_buf + bn_len, bn_len, ecdsa_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: if (eckey) { EC_KEY_free(eckey); } if (order) { BN_free(order); } if (wrong_eckey) { EC_KEY_free(wrong_eckey); } if (ecdsa_sig) { ECDSA_SIG_free(ecdsa_sig); } if (signature) { OPENSSL_free(signature); } if (raw_buf) { OPENSSL_free(raw_buf); } 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; }
bool CKey::Verify(uint256 hash, const std::vector<unsigned char>& vchSig) { if( fNewerOpenSSL ) { if (vchSig.empty()) return false; // New versions of OpenSSL will reject non-canonical DER signatures. de/re-serialize first. unsigned char *norm_der = NULL; ECDSA_SIG *norm_sig = ECDSA_SIG_new(); const unsigned char * sigptr = &vchSig[0]; Yassert(norm_sig); if (d2i_ECDSA_SIG(&norm_sig, &sigptr, vchSig.size()) == NULL) { /* As of OpenSSL 1.0.0p d2i_ECDSA_SIG frees and nulls the pointer on * error. But OpenSSL's own use of this function redundantly frees the * result. As ECDSA_SIG_free(NULL) is a no-op, and in the absence of a * clear contract for the function behaving the same way is more * conservative. */ ECDSA_SIG_free(norm_sig); return false; } int derlen = i2d_ECDSA_SIG(norm_sig, &norm_der); ECDSA_SIG_free(norm_sig); if (derlen <= 0) return false; // -1 = error, 0 = bad sig, 1 = good bool ret = ( 1 == ECDSA_verify( 0, (unsigned char*)&hash, sizeof(hash), norm_der, derlen, pkey ) ); OPENSSL_free(norm_der); if (false == ret) return false; return ret; } else // older version of OpenSSL, so do the old code { if (vchSig.empty()) { printf( "\n\aECDSA signature verify called with nul argument?\n\n" ); } const int nECDSAgood = 1, nECDSAbad = 0, nECDSAerror = -1; int nReturn = ECDSA_verify( 0, (unsigned char*)&hash, sizeof(hash), &vchSig[0], vchSig.size(), pkey ); switch( nReturn ) { case nECDSAgood: return true; case nECDSAbad: //printf( "\n\aECDSA signature verify FAILED?\n\n" ); //(void)MessageBeep( MB_ICONERROR ); return false; case nECDSAerror: //printf( "\n\aECDSA signature verify ERRORED?\n\n" ); //(void)MessageBeep( MB_ICONERROR ); return false; default: return false; } } }
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; }
int main(int argc, char * const argv[]) { int ret = EX_DATAERR; ssize_t cd_len, reg_len; unsigned char kh_len; unsigned const char *kh, *sig; size_t siglen; EVP_PKEY *pkey = NULL; unsigned char cp_hash[SHA256_DIGEST_LENGTH]; unsigned char ap_hash[SHA256_DIGEST_LENGTH]; EVP_MD_CTX ctx; X509 *crt = NULL; unsigned const char *ptr; int i; cd_len = strlen(clientData); reg_len = sizeof(registrationData); if (registrationData[0] != 0x05) { fprintf(stderr, "invalid header byte\n"); goto DONE; } /* key handle */ kh = registrationData+67; kh_len = registrationData[66]; /* parse attestation certificate (X.509) */ ptr = registrationData + 67 + kh_len; crt = d2i_X509(NULL, (const unsigned char**)&ptr, reg_len - (ptr-registrationData)); if (crt == NULL) { fprintf(stderr, "Error while parsing X509\n"); goto DONE; } /* check if this is a valid signature */ sig = ptr; ECDSA_SIG *ecsig = d2i_ECDSA_SIG(NULL, (const unsigned char**)&ptr, reg_len - (ptr-registrationData)); if (ecsig == NULL) { fprintf(stderr, "Error while reading signature\n"); ECDSA_SIG_free(ecsig); ecsig = NULL; goto DONE; } siglen = ptr-sig; ECDSA_SIG_free(ecsig); ecsig = NULL; /* extract public key from X509 attestation certificare */ pkey = X509_get_pubkey(crt); if (pkey == NULL) { fprintf(stderr, "Can't get public key!\n"); goto DONE; } /* generate SHA256 hash on challenge parameter and application parameter */ (void)SHA256((const unsigned char*)clientData, cd_len, cp_hash); (void)SHA256((const unsigned char*)appId, strlen(appId), ap_hash); /* verify signature */ if (EVP_VerifyInit(&ctx, EVP_sha256()) != 1) { fprintf(stderr, "EVP_VerifyInit() failed\n"); goto DONE; } (void)EVP_VerifyUpdate(&ctx, "\0", 1UL); (void)EVP_VerifyUpdate(&ctx, ap_hash, 32UL); (void)EVP_VerifyUpdate(&ctx, cp_hash, 32UL); (void)EVP_VerifyUpdate(&ctx, kh, (unsigned long)kh_len); (void)EVP_VerifyUpdate(&ctx, registrationData+1, 65UL); if ((i = EVP_VerifyFinal(&ctx, sig, siglen, pkey)) != 1) { fprintf(stderr, "EVP_VerifyFinal failed: err=%i, %s\n", i, ERR_error_string(ERR_get_error(), NULL)); (void)EVP_MD_CTX_cleanup(&ctx); goto DONE; } (void)EVP_MD_CTX_cleanup(&ctx); printf("Valid response.\n"); ret = EX_OK; DONE: if (crt != NULL) { X509_free(crt); crt = NULL; } if (pkey != NULL) { EVP_PKEY_free(pkey); pkey = NULL; } return(ret); }