/* Create ephemeral key and initialise context based on it */ static int cms_kari_create_ephemeral_key(CMS_KeyAgreeRecipientInfo *kari, EVP_PKEY *pk) { EVP_PKEY_CTX *pctx = NULL; EVP_PKEY *ekey = NULL; int rv = 0; pctx = EVP_PKEY_CTX_new(pk, NULL); if (!pctx) goto err; if (EVP_PKEY_keygen_init(pctx) <= 0) goto err; if (EVP_PKEY_keygen(pctx, &ekey) <= 0) goto err; EVP_PKEY_CTX_free(pctx); pctx = EVP_PKEY_CTX_new(ekey, NULL); if (!pctx) goto err; if (EVP_PKEY_derive_init(pctx) <= 0) goto err; kari->pctx = pctx; rv = 1; err: if (!rv) EVP_PKEY_CTX_free(pctx); EVP_PKEY_free(ekey); return rv; }
struct dh_message *dh_shared_secret(EVP_PKEY *priv_key, EVP_PKEY *peer_key) { EVP_PKEY_CTX *derive_ctx; struct dh_message *msg = NULL, *digest = NULL; if ((msg = OPENSSL_malloc(sizeof(struct dh_message))) == NULL) return NULL; if ((derive_ctx = EVP_PKEY_CTX_new(priv_key, NULL)) == NULL) goto BAILOUT1; if (EVP_PKEY_derive_init(derive_ctx) != 1 || EVP_PKEY_derive_set_peer(derive_ctx, peer_key) != 1 || EVP_PKEY_derive(derive_ctx, NULL, &msg->message_len) != 1 || (msg->message = OPENSSL_malloc(msg->message_len)) == NULL) goto BAILOUT2; if (EVP_PKEY_derive(derive_ctx, msg->message, &msg->message_len) != 1) goto BAILOUT3; EVP_PKEY_CTX_free(derive_ctx); digest = digest_message(msg); free_dh_message(msg); return digest; BAILOUT3: OPENSSL_free(msg->message); BAILOUT2: EVP_PKEY_CTX_free(derive_ctx); BAILOUT1: OPENSSL_free(msg); return NULL; }
soter_status_t soter_asym_ka_derive(soter_asym_ka_t* asym_ka_ctx, const void* peer_key, size_t peer_key_length, void *shared_secret, size_t* shared_secret_length) { EVP_PKEY *peer_pkey = EVP_PKEY_new(); soter_status_t res; size_t out_length; if (NULL == peer_pkey) { return SOTER_NO_MEMORY; } if ((!asym_ka_ctx) || (!shared_secret_length)) { EVP_PKEY_free(peer_pkey); return SOTER_INVALID_PARAMETER; } res = soter_ec_pub_key_to_engine_specific((const soter_container_hdr_t *)peer_key, peer_key_length, ((soter_engine_specific_ec_key_t **)&peer_pkey)); if (SOTER_SUCCESS != res) { EVP_PKEY_free(peer_pkey); return res; } if (1 != EVP_PKEY_derive_init(asym_ka_ctx->pkey_ctx)) { EVP_PKEY_free(peer_pkey); return SOTER_FAIL; } if (1 != EVP_PKEY_derive_set_peer(asym_ka_ctx->pkey_ctx, peer_pkey)) { EVP_PKEY_free(peer_pkey); return SOTER_FAIL; } if (1 != EVP_PKEY_derive(asym_ka_ctx->pkey_ctx, NULL, &out_length)) { EVP_PKEY_free(peer_pkey); return SOTER_FAIL; } if (out_length > *shared_secret_length) { EVP_PKEY_free(peer_pkey); *shared_secret_length = out_length; return SOTER_BUFFER_TOO_SMALL; } if (1 != EVP_PKEY_derive(asym_ka_ctx->pkey_ctx, (unsigned char *)shared_secret, shared_secret_length)) { EVP_PKEY_free(peer_pkey); return SOTER_FAIL; } EVP_PKEY_free(peer_pkey); return SOTER_SUCCESS; }
/* * Given a |secret|; a |label| of length |labellen|; and a |hash| of the * handshake messages, derive a new secret |outlen| bytes long and store it in * the location pointed to be |out|. The |hash| value may be NULL. Returns 1 on * success 0 on failure. */ static int tls13_hkdf_expand(SSL *s, const unsigned char *secret, const unsigned char *label, size_t labellen, const unsigned char *hash, unsigned char *out, size_t outlen) { const unsigned char label_prefix[] = "TLS 1.3, "; const EVP_MD *md = ssl_handshake_md(s); EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); int ret; size_t hkdflabellen; size_t hashlen; /* * 2 bytes for length of whole HkdfLabel + 1 byte for length of combined * prefix and label + bytes for the label itself + bytes for the hash */ unsigned char hkdflabel[sizeof(uint16_t) + sizeof(uint8_t) + + sizeof(label_prefix) + TLS13_MAX_LABEL_LEN + EVP_MAX_MD_SIZE]; WPACKET pkt; if (pctx == NULL) return 0; hashlen = EVP_MD_size(md); if (!WPACKET_init_static_len(&pkt, hkdflabel, sizeof(hkdflabel), 0) || !WPACKET_put_bytes_u16(&pkt, outlen) || !WPACKET_start_sub_packet_u8(&pkt) || !WPACKET_memcpy(&pkt, label_prefix, sizeof(label_prefix) - 1) || !WPACKET_memcpy(&pkt, label, labellen) || !WPACKET_close(&pkt) || !WPACKET_sub_memcpy_u8(&pkt, hash, (hash == NULL) ? 0 : hashlen) || !WPACKET_get_total_written(&pkt, &hkdflabellen) || !WPACKET_finish(&pkt)) { WPACKET_cleanup(&pkt); return 0; } ret = EVP_PKEY_derive_init(pctx) <= 0 || EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) <= 0 || EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0 || EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, hashlen) <= 0 || EVP_PKEY_CTX_add1_hkdf_info(pctx, hkdflabel, hkdflabellen) <= 0 || EVP_PKEY_derive(pctx, out, &outlen) <= 0; EVP_PKEY_CTX_free(pctx); return ret == 0; }
static int test_kdf_hkdf(void) { int ret = 0; EVP_PKEY_CTX *pctx; unsigned char out[10]; size_t outlen = sizeof(out); if ((pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL)) == NULL) { TEST_error("EVP_PKEY_HKDF"); goto err; } if (EVP_PKEY_derive_init(pctx) <= 0) { TEST_error("EVP_PKEY_derive_init"); goto err; } if (EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256()) <= 0) { TEST_error("EVP_PKEY_CTX_set_hkdf_md"); goto err; } if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, "salt", 4) <= 0) { TEST_error("EVP_PKEY_CTX_set1_hkdf_salt"); goto err; } if (EVP_PKEY_CTX_set1_hkdf_key(pctx, "secret", 6) <= 0) { TEST_error("EVP_PKEY_CTX_set1_hkdf_key"); goto err; } if (EVP_PKEY_CTX_add1_hkdf_info(pctx, "label", 5) <= 0) { TEST_error("EVP_PKEY_CTX_set1_hkdf_info"); goto err; } if (EVP_PKEY_derive(pctx, out, &outlen) <= 0) { TEST_error("EVP_PKEY_derive"); goto err; } { const unsigned char expected[sizeof(out)] = { 0x2a, 0xc4, 0x36, 0x9f, 0x52, 0x59, 0x96, 0xf8, 0xde, 0x13 }; if (!TEST_mem_eq(out, sizeof(out), expected, sizeof(expected))) { goto err; } } ret = 1; err: EVP_PKEY_CTX_free(pctx); return ret; }
static int test_kdf_tls1_prf(void) { int ret = 0; EVP_PKEY_CTX *pctx; unsigned char out[16]; size_t outlen = sizeof(out); if ((pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_TLS1_PRF, NULL)) == NULL) { TEST_error("EVP_PKEY_TLS1_PRF"); goto err; } if (EVP_PKEY_derive_init(pctx) <= 0) { TEST_error("EVP_PKEY_derive_init"); goto err; } if (EVP_PKEY_CTX_set_tls1_prf_md(pctx, EVP_sha256()) <= 0) { TEST_error("EVP_PKEY_CTX_set_tls1_prf_md"); goto err; } if (EVP_PKEY_CTX_set1_tls1_prf_secret(pctx, "secret", 6) <= 0) { TEST_error("EVP_PKEY_CTX_set1_tls1_prf_secret"); goto err; } if (EVP_PKEY_CTX_add1_tls1_prf_seed(pctx, "seed", 4) <= 0) { TEST_error("EVP_PKEY_CTX_add1_tls1_prf_seed"); goto err; } if (EVP_PKEY_derive(pctx, out, &outlen) <= 0) { TEST_error("EVP_PKEY_derive"); goto err; } { const unsigned char expected[sizeof(out)] = { 0x8e, 0x4d, 0x93, 0x25, 0x30, 0xd7, 0x65, 0xa0, 0xaa, 0xe9, 0x74, 0xc3, 0x04, 0x73, 0x5e, 0xcc }; if (!TEST_mem_eq(out, sizeof(out), expected, sizeof(expected))) { goto err; } } ret = 1; err: EVP_PKEY_CTX_free(pctx); return ret; }
int CMS_RecipientInfo_kari_set0_pkey(CMS_RecipientInfo *ri, EVP_PKEY *pk) { EVP_PKEY_CTX *pctx; CMS_KeyAgreeRecipientInfo *kari = ri->d.kari; EVP_PKEY_CTX_free(kari->pctx); kari->pctx = NULL; if (!pk) return 1; pctx = EVP_PKEY_CTX_new(pk, NULL); if (!pctx || !EVP_PKEY_derive_init(pctx)) goto err; kari->pctx = pctx; return 1; err: EVP_PKEY_CTX_free(pctx); return 0; }
static int test_HKDF(void) { EVP_PKEY_CTX *pctx; unsigned char out[20]; size_t outlen; int i, ret = 0; unsigned char salt[] = "0123456789"; unsigned char key[] = "012345678901234567890123456789"; unsigned char info[] = "infostring"; const unsigned char expected[] = { 0xe5, 0x07, 0x70, 0x7f, 0xc6, 0x78, 0xd6, 0x54, 0x32, 0x5f, 0x7e, 0xc5, 0x7b, 0x59, 0x3e, 0xd8, 0x03, 0x6b, 0xed, 0xca }; size_t expectedlen = sizeof(expected); if (!TEST_ptr(pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL))) goto done; /* We do this twice to test reuse of the EVP_PKEY_CTX */ for (i = 0; i < 2; i++) { outlen = sizeof(out); memset(out, 0, outlen); if (!TEST_int_gt(EVP_PKEY_derive_init(pctx), 0) || !TEST_int_gt(EVP_PKEY_CTX_set_hkdf_md(pctx, EVP_sha256()), 0) || !TEST_int_gt(EVP_PKEY_CTX_set1_hkdf_salt(pctx, salt, sizeof(salt) - 1), 0) || !TEST_int_gt(EVP_PKEY_CTX_set1_hkdf_key(pctx, key, sizeof(key) - 1), 0) || !TEST_int_gt(EVP_PKEY_CTX_add1_hkdf_info(pctx, info, sizeof(info) - 1), 0) || !TEST_int_gt(EVP_PKEY_derive(pctx, out, &outlen), 0) || !TEST_mem_eq(out, outlen, expected, expectedlen)) goto done; } ret = 1; done: EVP_PKEY_CTX_free(pctx); return ret; }
/* * Given the previous secret |prevsecret| and a new input secret |insecret| of * length |insecretlen|, generate a new secret and store it in the location * pointed to by |outsecret|. Returns 1 on success 0 on failure. */ static int tls13_generate_secret(SSL *s, const unsigned char *prevsecret, const unsigned char *insecret, size_t insecretlen, unsigned char *outsecret) { const EVP_MD *md = ssl_handshake_md(s); size_t mdlen, prevsecretlen; int ret; EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); if (pctx == NULL) return 0; mdlen = EVP_MD_size(md); if (insecret == NULL) { insecret = default_zeros; insecretlen = mdlen; } if (prevsecret == NULL) { prevsecret = default_zeros; prevsecretlen = 0; } else { prevsecretlen = mdlen; } ret = EVP_PKEY_derive_init(pctx) <= 0 || EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY) <= 0 || EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0 || EVP_PKEY_CTX_set1_hkdf_key(pctx, insecret, insecretlen) <= 0 || EVP_PKEY_CTX_set1_hkdf_salt(pctx, prevsecret, prevsecretlen) <= 0 || EVP_PKEY_derive(pctx, outsecret, &mdlen) <= 0; EVP_PKEY_CTX_free(pctx); return ret == 0; }
/* * Given the previous secret |prevsecret| and a new input secret |insecret| of * length |insecretlen|, generate a new secret and store it in the location * pointed to by |outsecret|. Returns 1 on success 0 on failure. */ int tls13_generate_secret(SSL *s, const EVP_MD *md, const unsigned char *prevsecret, const unsigned char *insecret, size_t insecretlen, unsigned char *outsecret) { size_t mdlen, prevsecretlen; int mdleni; int ret; EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); static const char derived_secret_label[] = "derived"; unsigned char preextractsec[EVP_MAX_MD_SIZE]; if (pctx == NULL) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_GENERATE_SECRET, ERR_R_INTERNAL_ERROR); return 0; } mdleni = EVP_MD_size(md); /* Ensure cast to size_t is safe */ if (!ossl_assert(mdleni >= 0)) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_GENERATE_SECRET, ERR_R_INTERNAL_ERROR); return 0; } mdlen = (size_t)mdleni; if (insecret == NULL) { insecret = default_zeros; insecretlen = mdlen; } if (prevsecret == NULL) { prevsecret = default_zeros; prevsecretlen = 0; } else { EVP_MD_CTX *mctx = EVP_MD_CTX_new(); unsigned char hash[EVP_MAX_MD_SIZE]; /* The pre-extract derive step uses a hash of no messages */ if (mctx == NULL || EVP_DigestInit_ex(mctx, md, NULL) <= 0 || EVP_DigestFinal_ex(mctx, hash, NULL) <= 0) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_GENERATE_SECRET, ERR_R_INTERNAL_ERROR); EVP_MD_CTX_free(mctx); EVP_PKEY_CTX_free(pctx); return 0; } EVP_MD_CTX_free(mctx); /* Generate the pre-extract secret */ if (!tls13_hkdf_expand(s, md, prevsecret, (unsigned char *)derived_secret_label, sizeof(derived_secret_label) - 1, hash, mdlen, preextractsec, mdlen, 1)) { /* SSLfatal() already called */ EVP_PKEY_CTX_free(pctx); return 0; } prevsecret = preextractsec; prevsecretlen = mdlen; } ret = EVP_PKEY_derive_init(pctx) <= 0 || EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY) <= 0 || EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0 || EVP_PKEY_CTX_set1_hkdf_key(pctx, insecret, insecretlen) <= 0 || EVP_PKEY_CTX_set1_hkdf_salt(pctx, prevsecret, prevsecretlen) <= 0 || EVP_PKEY_derive(pctx, outsecret, &mdlen) <= 0; if (ret != 0) SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_GENERATE_SECRET, ERR_R_INTERNAL_ERROR); EVP_PKEY_CTX_free(pctx); if (prevsecret == preextractsec) OPENSSL_cleanse(preextractsec, mdlen); return ret == 0; }
cjose_jwk_t *cjose_jwk_derive_ecdh_ephemeral_key( cjose_jwk_t *jwk_self, cjose_jwk_t *jwk_peer, cjose_err *err) { EVP_PKEY_CTX *ctx = NULL; EVP_PKEY *pkey_self = NULL; EVP_PKEY *pkey_peer = NULL; uint8_t *secret = NULL; size_t secret_len = 0; uint8_t *ephemeral_key = NULL; size_t ephemeral_key_len = 0; cjose_jwk_t *jwk_ephemeral_key = NULL; // get EVP_KEY from jwk_self if (!_cjose_jwk_evp_key_from_ec_key(jwk_self, &pkey_self, err)) { goto _cjose_jwk_derive_shared_secret_fail; } // get EVP_KEY from jwk_peer if (!_cjose_jwk_evp_key_from_ec_key(jwk_peer, &pkey_peer, err)) { goto _cjose_jwk_derive_shared_secret_fail; } // create derivation context based on local key pair ctx = EVP_PKEY_CTX_new(pkey_self, NULL); if (NULL == ctx) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); goto _cjose_jwk_derive_shared_secret_fail; } // initialize derivation context if (1 != EVP_PKEY_derive_init(ctx)) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); goto _cjose_jwk_derive_shared_secret_fail; } // provide the peer public key if (1 != EVP_PKEY_derive_set_peer(ctx, pkey_peer)) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); goto _cjose_jwk_derive_shared_secret_fail; } // determine buffer length for shared secret if(1 != EVP_PKEY_derive(ctx, NULL, &secret_len)) { CJOSE_ERROR(err, CJOSE_ERR_CRYPTO); goto _cjose_jwk_derive_shared_secret_fail; } // allocate buffer for shared secret secret = (uint8_t *)cjose_get_alloc()(secret_len); if (NULL == secret) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); goto _cjose_jwk_derive_shared_secret_fail; } memset(secret, 0, secret_len); // derive the shared secret if (1 != (EVP_PKEY_derive(ctx, secret, &secret_len))) { CJOSE_ERROR(err, CJOSE_ERR_NO_MEMORY); goto _cjose_jwk_derive_shared_secret_fail; } // HKDF of the DH shared secret (SHA256, no salt, no info, 256 bit expand) ephemeral_key_len = 32; ephemeral_key = (uint8_t *)cjose_get_alloc()(ephemeral_key_len); if (!cjose_jwk_hkdf(EVP_sha256(), (uint8_t *)"", 0, (uint8_t *)"", 0, secret, secret_len, ephemeral_key, ephemeral_key_len, err)) { goto _cjose_jwk_derive_shared_secret_fail; } // create a JWK of the shared secret jwk_ephemeral_key = cjose_jwk_create_oct_spec( ephemeral_key, ephemeral_key_len, err); if (NULL == jwk_ephemeral_key) { goto _cjose_jwk_derive_shared_secret_fail; } // happy path EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pkey_self); EVP_PKEY_free(pkey_peer); cjose_get_dealloc()(secret); cjose_get_dealloc()(ephemeral_key); return jwk_ephemeral_key; // fail path _cjose_jwk_derive_shared_secret_fail: if (NULL != ctx) { EVP_PKEY_CTX_free(ctx); } if (NULL != pkey_self) { EVP_PKEY_free(pkey_self); } if (NULL != pkey_peer) { EVP_PKEY_free(pkey_peer); } if (NULL != jwk_ephemeral_key) { cjose_jwk_release(jwk_ephemeral_key); } cjose_get_dealloc()(secret); cjose_get_dealloc()(ephemeral_key); return NULL; }
static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, const char *keyfile, int keyform, int key_type, char *passinarg, int pkey_op, ENGINE *e, const int engine_impl, EVP_PKEY **ppkey) { EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *ctx = NULL; ENGINE *impl = NULL; char *passin = NULL; int rv = -1; X509 *x; if (((pkey_op == EVP_PKEY_OP_SIGN) || (pkey_op == EVP_PKEY_OP_DECRYPT) || (pkey_op == EVP_PKEY_OP_DERIVE)) && (key_type != KEY_PRIVKEY && kdfalg == NULL)) { BIO_printf(bio_err, "A private key is needed for this operation\n"); goto end; } if (!app_passwd(passinarg, NULL, &passin, NULL)) { BIO_printf(bio_err, "Error getting password\n"); goto end; } switch (key_type) { case KEY_PRIVKEY: pkey = load_key(keyfile, keyform, 0, passin, e, "Private Key"); break; case KEY_PUBKEY: pkey = load_pubkey(keyfile, keyform, 0, NULL, e, "Public Key"); break; case KEY_CERT: x = load_cert(keyfile, keyform, "Certificate"); if (x) { pkey = X509_get_pubkey(x); X509_free(x); } break; case KEY_NONE: break; } #ifndef OPENSSL_NO_ENGINE if (engine_impl) impl = e; #endif if (kdfalg != NULL) { int kdfnid = OBJ_sn2nid(kdfalg); if (kdfnid == NID_undef) { kdfnid = OBJ_ln2nid(kdfalg); if (kdfnid == NID_undef) { BIO_printf(bio_err, "The given KDF \"%s\" is unknown.\n", kdfalg); goto end; } } ctx = EVP_PKEY_CTX_new_id(kdfnid, impl); } else { EC_KEY *eckey = NULL; const EC_GROUP *group = NULL; int nid; if (pkey == NULL) goto end; /* SM2 needs a special treatment */ if (EVP_PKEY_id(pkey) == EVP_PKEY_EC) { if ((eckey = EVP_PKEY_get0_EC_KEY(pkey)) == NULL || (group = EC_KEY_get0_group(eckey)) == NULL || (nid = EC_GROUP_get_curve_name(group)) == 0) goto end; if (nid == NID_sm2) EVP_PKEY_set_alias_type(pkey, EVP_PKEY_SM2); } *pkeysize = EVP_PKEY_size(pkey); ctx = EVP_PKEY_CTX_new(pkey, impl); if (ppkey != NULL) *ppkey = pkey; EVP_PKEY_free(pkey); } if (ctx == NULL) goto end; switch (pkey_op) { case EVP_PKEY_OP_SIGN: rv = EVP_PKEY_sign_init(ctx); break; case EVP_PKEY_OP_VERIFY: rv = EVP_PKEY_verify_init(ctx); break; case EVP_PKEY_OP_VERIFYRECOVER: rv = EVP_PKEY_verify_recover_init(ctx); break; case EVP_PKEY_OP_ENCRYPT: rv = EVP_PKEY_encrypt_init(ctx); break; case EVP_PKEY_OP_DECRYPT: rv = EVP_PKEY_decrypt_init(ctx); break; case EVP_PKEY_OP_DERIVE: rv = EVP_PKEY_derive_init(ctx); break; } if (rv <= 0) { EVP_PKEY_CTX_free(ctx); ctx = NULL; } end: OPENSSL_free(passin); return ctx; }
static EVP_PKEY_CTX *init_ctx(const char *kdfalg, int *pkeysize, const char *keyfile, int keyform, int key_type, char *passinarg, int pkey_op, ENGINE *e, const int engine_impl) { EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *ctx = NULL; ENGINE *impl = NULL; char *passin = NULL; int rv = -1; X509 *x; if (((pkey_op == EVP_PKEY_OP_SIGN) || (pkey_op == EVP_PKEY_OP_DECRYPT) || (pkey_op == EVP_PKEY_OP_DERIVE)) && (key_type != KEY_PRIVKEY && kdfalg == NULL)) { BIO_printf(bio_err, "A private key is needed for this operation\n"); goto end; } if (!app_passwd(passinarg, NULL, &passin, NULL)) { BIO_printf(bio_err, "Error getting password\n"); goto end; } switch (key_type) { case KEY_PRIVKEY: pkey = load_key(keyfile, keyform, 0, passin, e, "Private Key"); break; case KEY_PUBKEY: pkey = load_pubkey(keyfile, keyform, 0, NULL, e, "Public Key"); break; case KEY_CERT: x = load_cert(keyfile, keyform, "Certificate"); if (x) { pkey = X509_get_pubkey(x); X509_free(x); } break; case KEY_NONE: break; } #ifndef OPENSSL_NO_ENGINE if (engine_impl) impl = e; #endif if (kdfalg) { int kdfnid = OBJ_sn2nid(kdfalg); if (kdfnid == NID_undef) goto end; ctx = EVP_PKEY_CTX_new_id(kdfnid, impl); } else { if (pkey == NULL) goto end; *pkeysize = EVP_PKEY_size(pkey); ctx = EVP_PKEY_CTX_new(pkey, impl); EVP_PKEY_free(pkey); } if (ctx == NULL) goto end; switch (pkey_op) { case EVP_PKEY_OP_SIGN: rv = EVP_PKEY_sign_init(ctx); break; case EVP_PKEY_OP_VERIFY: rv = EVP_PKEY_verify_init(ctx); break; case EVP_PKEY_OP_VERIFYRECOVER: rv = EVP_PKEY_verify_recover_init(ctx); break; case EVP_PKEY_OP_ENCRYPT: rv = EVP_PKEY_encrypt_init(ctx); break; case EVP_PKEY_OP_DECRYPT: rv = EVP_PKEY_decrypt_init(ctx); break; case EVP_PKEY_OP_DERIVE: rv = EVP_PKEY_derive_init(ctx); break; } if (rv <= 0) { EVP_PKEY_CTX_free(ctx); ctx = NULL; } end: OPENSSL_free(passin); return ctx; }
static int test_kdf_scrypt(void) { int ret = 0; EVP_PKEY_CTX *pctx; unsigned char out[64]; size_t outlen = sizeof(out); if ((pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_SCRYPT, NULL)) == NULL) { TEST_error("EVP_PKEY_SCRYPT"); goto err; } if (EVP_PKEY_derive_init(pctx) <= 0) { TEST_error("EVP_PKEY_derive_init"); goto err; } if (EVP_PKEY_CTX_set1_pbe_pass(pctx, "password", 8) <= 0) { TEST_error("EVP_PKEY_CTX_set1_pbe_pass"); goto err; } if (EVP_PKEY_CTX_set1_scrypt_salt(pctx, "NaCl", 4) <= 0) { TEST_error("EVP_PKEY_CTX_set1_scrypt_salt"); goto err; } if (EVP_PKEY_CTX_set_scrypt_N(pctx, 1024) <= 0) { TEST_error("EVP_PKEY_CTX_set_scrypt_N"); goto err; } if (EVP_PKEY_CTX_set_scrypt_r(pctx, 8) <= 0) { TEST_error("EVP_PKEY_CTX_set_scrypt_r"); goto err; } if (EVP_PKEY_CTX_set_scrypt_p(pctx, 16) <= 0) { TEST_error("EVP_PKEY_CTX_set_scrypt_p"); goto err; } if (EVP_PKEY_CTX_set_scrypt_maxmem_bytes(pctx, 16) <= 0) { TEST_error("EVP_PKEY_CTX_set_maxmem_bytes"); goto err; } if (EVP_PKEY_derive(pctx, out, &outlen) > 0) { TEST_error("EVP_PKEY_derive should have failed"); goto err; } if (EVP_PKEY_CTX_set_scrypt_maxmem_bytes(pctx, 10 * 1024 * 1024) <= 0) { TEST_error("EVP_PKEY_CTX_set_maxmem_bytes"); goto err; } if (EVP_PKEY_derive(pctx, out, &outlen) <= 0) { TEST_error("EVP_PKEY_derive"); goto err; } { const unsigned char expected[sizeof(out)] = { 0xfd, 0xba, 0xbe, 0x1c, 0x9d, 0x34, 0x72, 0x00, 0x78, 0x56, 0xe7, 0x19, 0x0d, 0x01, 0xe9, 0xfe, 0x7c, 0x6a, 0xd7, 0xcb, 0xc8, 0x23, 0x78, 0x30, 0xe7, 0x73, 0x76, 0x63, 0x4b, 0x37, 0x31, 0x62, 0x2e, 0xaf, 0x30, 0xd9, 0x2e, 0x22, 0xa3, 0x88, 0x6f, 0xf1, 0x09, 0x27, 0x9d, 0x98, 0x30, 0xda, 0xc7, 0x27, 0xaf, 0xb9, 0x4a, 0x83, 0xee, 0x6d, 0x83, 0x60, 0xcb, 0xdf, 0xa2, 0xcc, 0x06, 0x40 }; if (!TEST_mem_eq(out, sizeof(out), expected, sizeof(expected))) { goto err; } } ret = 1; err: EVP_PKEY_CTX_free(pctx); return ret; }
/* * Given a |secret|; a |label| of length |labellen|; and |data| of length * |datalen| (e.g. typically a hash of the handshake messages), derive a new * secret |outlen| bytes long and store it in the location pointed to be |out|. * The |data| value may be zero length. Any errors will be treated as fatal if * |fatal| is set. Returns 1 on success 0 on failure. */ int tls13_hkdf_expand(SSL *s, const EVP_MD *md, const unsigned char *secret, const unsigned char *label, size_t labellen, const unsigned char *data, size_t datalen, unsigned char *out, size_t outlen, int fatal) { static const unsigned char label_prefix[] = "tls13 "; EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); int ret; size_t hkdflabellen; size_t hashlen; /* * 2 bytes for length of derived secret + 1 byte for length of combined * prefix and label + bytes for the label itself + 1 byte length of hash * + bytes for the hash itself */ unsigned char hkdflabel[sizeof(uint16_t) + sizeof(uint8_t) + + sizeof(label_prefix) + TLS13_MAX_LABEL_LEN + 1 + EVP_MAX_MD_SIZE]; WPACKET pkt; if (pctx == NULL) return 0; if (labellen > TLS13_MAX_LABEL_LEN) { if (fatal) { SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_HKDF_EXPAND, ERR_R_INTERNAL_ERROR); } else { /* * Probably we have been called from SSL_export_keying_material(), * or SSL_export_keying_material_early(). */ SSLerr(SSL_F_TLS13_HKDF_EXPAND, SSL_R_TLS_ILLEGAL_EXPORTER_LABEL); } EVP_PKEY_CTX_free(pctx); return 0; } hashlen = EVP_MD_size(md); if (!WPACKET_init_static_len(&pkt, hkdflabel, sizeof(hkdflabel), 0) || !WPACKET_put_bytes_u16(&pkt, outlen) || !WPACKET_start_sub_packet_u8(&pkt) || !WPACKET_memcpy(&pkt, label_prefix, sizeof(label_prefix) - 1) || !WPACKET_memcpy(&pkt, label, labellen) || !WPACKET_close(&pkt) || !WPACKET_sub_memcpy_u8(&pkt, data, (data == NULL) ? 0 : datalen) || !WPACKET_get_total_written(&pkt, &hkdflabellen) || !WPACKET_finish(&pkt)) { EVP_PKEY_CTX_free(pctx); WPACKET_cleanup(&pkt); if (fatal) SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_HKDF_EXPAND, ERR_R_INTERNAL_ERROR); else SSLerr(SSL_F_TLS13_HKDF_EXPAND, ERR_R_INTERNAL_ERROR); return 0; } ret = EVP_PKEY_derive_init(pctx) <= 0 || EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) <= 0 || EVP_PKEY_CTX_set_hkdf_md(pctx, md) <= 0 || EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, hashlen) <= 0 || EVP_PKEY_CTX_add1_hkdf_info(pctx, hkdflabel, hkdflabellen) <= 0 || EVP_PKEY_derive(pctx, out, &outlen) <= 0; EVP_PKEY_CTX_free(pctx); if (ret != 0) { if (fatal) SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS13_HKDF_EXPAND, ERR_R_INTERNAL_ERROR); else SSLerr(SSL_F_TLS13_HKDF_EXPAND, ERR_R_INTERNAL_ERROR); } return ret == 0; }
static EVP_PKEY_CTX * init_ctx(int *pkeysize, char *keyfile, int keyform, int key_type, char *passargin, int pkey_op) { EVP_PKEY *pkey = NULL; EVP_PKEY_CTX *ctx = NULL; char *passin = NULL; int rv = -1; X509 *x; if (((pkey_op == EVP_PKEY_OP_SIGN) || (pkey_op == EVP_PKEY_OP_DECRYPT) || (pkey_op == EVP_PKEY_OP_DERIVE)) && (key_type != KEY_PRIVKEY)) { BIO_printf(bio_err, "A private key is needed for this operation\n"); goto end; } if (!app_passwd(bio_err, passargin, NULL, &passin, NULL)) { BIO_printf(bio_err, "Error getting password\n"); goto end; } switch (key_type) { case KEY_PRIVKEY: pkey = load_key(bio_err, keyfile, keyform, 0, passin, "Private Key"); break; case KEY_PUBKEY: pkey = load_pubkey(bio_err, keyfile, keyform, 0, NULL, "Public Key"); break; case KEY_CERT: x = load_cert(bio_err, keyfile, keyform, NULL, "Certificate"); if (x) { pkey = X509_get_pubkey(x); X509_free(x); } break; } *pkeysize = EVP_PKEY_size(pkey); if (!pkey) goto end; ctx = EVP_PKEY_CTX_new(pkey, NULL); EVP_PKEY_free(pkey); if (!ctx) goto end; switch (pkey_op) { case EVP_PKEY_OP_SIGN: rv = EVP_PKEY_sign_init(ctx); break; case EVP_PKEY_OP_VERIFY: rv = EVP_PKEY_verify_init(ctx); break; case EVP_PKEY_OP_VERIFYRECOVER: rv = EVP_PKEY_verify_recover_init(ctx); break; case EVP_PKEY_OP_ENCRYPT: rv = EVP_PKEY_encrypt_init(ctx); break; case EVP_PKEY_OP_DECRYPT: rv = EVP_PKEY_decrypt_init(ctx); break; case EVP_PKEY_OP_DERIVE: rv = EVP_PKEY_derive_init(ctx); break; } if (rv <= 0) { EVP_PKEY_CTX_free(ctx); ctx = NULL; } end: free(passin); return ctx; }
int main() { EVP_PKEY_CTX *pctx, *kctx; EVP_PKEY_CTX *ctx; unsigned char *secret; EVP_PKEY *pkey = NULL, *peerkey, *params = NULL; /* NB: assumes pkey, peerkey have been already set up */ /* Create the context for parameter generation */ if(NULL == (pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL))) handleErrors(); /* Initialise the parameter generation */ if(1 != EVP_PKEY_paramgen_init(pctx)) handleErrors(); /* We're going to use the ANSI X9.62 Prime 256v1 curve */ if(1 != EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, NID_X9_62_prime256v1)) handleErrors(); /* Create the parameter object params */ if (!EVP_PKEY_paramgen(pctx, ¶ms)) handleErrors(); /* Create the context for the key generation */ if(NULL == (kctx = EVP_PKEY_CTX_new(params, NULL))) handleErrors(); /* Generate the key */ if(1 != EVP_PKEY_keygen_init(kctx)) handleErrors(); if (1 != EVP_PKEY_keygen(kctx, &pkey)) handleErrors(); /* Get the peer's public key, and provide the peer with our public key - * how this is done will be specific to your circumstances */ peerkey = get_peerkey(pkey); /* Create the context for the shared secret derivation */ if(NULL == (ctx = EVP_PKEY_CTX_new(pkey, NULL))) handleErrors(); /* Initialise */ if(1 != EVP_PKEY_derive_init(ctx)) handleErrors(); /* Provide the peer public key */ if(1 != EVP_PKEY_derive_set_peer(ctx, peerkey)) handleErrors(); /* Determine buffer length for shared secret */ if(1 != EVP_PKEY_derive(ctx, NULL, secret_len)) handleErrors(); /* Create the buffer */ if(NULL == (secret = OPENSSL_malloc(*secret_len))) handleErrors(); /* Derive the shared secret */ if(1 != (EVP_PKEY_derive(ctx, secret, secret_len))) handleErrors(); EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(peerkey); EVP_PKEY_free(pkey); EVP_PKEY_CTX_free(kctx); EVP_PKEY_free(params); EVP_PKEY_CTX_free(pctx); /* Never use a derived secret directly. Typically it is passed * through some hash function to produce a key */ return 0; }