int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, EVP_KEYEXCH *exchange)
{
    int ret;
    void *provkey = NULL;
    ctx->operation = EVP_PKEY_OP_DERIVE;
    if (ctx->engine != NULL)
        goto legacy;
    if (exchange != NULL) {
        if (!EVP_KEYEXCH_up_ref(exchange))
            goto err;
    } else {
        int nid = ctx->pkey != NULL ? ctx->pkey->type : ctx->pmeth->pkey_id;
        if (ctx->pkey != NULL) {
            switch (ctx->pkey->type) {
            case EVP_PKEY_DH:
                break;
            default:
                goto legacy;
            }
            exchange = EVP_KEYEXCH_fetch(NULL, OBJ_nid2sn(nid), NULL);
        } else {
            goto legacy;
        }
        if (exchange == NULL) {
            EVPerr(EVP_F_EVP_PKEY_DERIVE_INIT_EX, EVP_R_INITIALIZATION_ERROR);
            goto err;
        }
    }
    if (ctx->exchprovctx != NULL && ctx->exchange != NULL)
        ctx->exchange->freectx(ctx->exchprovctx);
    EVP_KEYEXCH_free(ctx->exchange);
    ctx->exchange = exchange;
    if (ctx->pkey != NULL) {
        provkey = evp_keymgmt_export_to_provider(ctx->pkey, exchange->keymgmt);
        if (provkey == NULL) {
            EVPerr(EVP_F_EVP_PKEY_DERIVE_INIT_EX, EVP_R_INITIALIZATION_ERROR);
            goto err;
        }
    }
    ctx->exchprovctx = exchange->newctx(ossl_provider_ctx(exchange->prov));
    if (ctx->exchprovctx == NULL) {
        EVPerr(EVP_F_EVP_PKEY_DERIVE_INIT_EX, EVP_R_INITIALIZATION_ERROR);
        goto err;
    }
    ret = exchange->init(ctx->exchprovctx, provkey);
    return ret ? 1 : 0;
 err:
    ctx->operation = EVP_PKEY_OP_UNDEFINED;
    return 0;
 legacy:
    if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->derive == NULL) {
        EVPerr(EVP_F_EVP_PKEY_DERIVE_INIT_EX,
               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);
        return -2;
    }
    if (ctx->pmeth->derive_init == NULL)
        return 1;
    ret = ctx->pmeth->derive_init(ctx);
    if (ret <= 0)
        ctx->operation = EVP_PKEY_OP_UNDEFINED;
    return ret;
}
['int EVP_PKEY_derive_init_ex(EVP_PKEY_CTX *ctx, EVP_KEYEXCH *exchange)\n{\n    int ret;\n    void *provkey = NULL;\n    ctx->operation = EVP_PKEY_OP_DERIVE;\n    if (ctx->engine != NULL)\n        goto legacy;\n    if (exchange != NULL) {\n        if (!EVP_KEYEXCH_up_ref(exchange))\n            goto err;\n    } else {\n        int nid = ctx->pkey != NULL ? ctx->pkey->type : ctx->pmeth->pkey_id;\n        if (ctx->pkey != NULL) {\n            switch (ctx->pkey->type) {\n            case EVP_PKEY_DH:\n                break;\n            default:\n                goto legacy;\n            }\n            exchange = EVP_KEYEXCH_fetch(NULL, OBJ_nid2sn(nid), NULL);\n        } else {\n            goto legacy;\n        }\n        if (exchange == NULL) {\n            EVPerr(EVP_F_EVP_PKEY_DERIVE_INIT_EX, EVP_R_INITIALIZATION_ERROR);\n            goto err;\n        }\n    }\n    if (ctx->exchprovctx != NULL && ctx->exchange != NULL)\n        ctx->exchange->freectx(ctx->exchprovctx);\n    EVP_KEYEXCH_free(ctx->exchange);\n    ctx->exchange = exchange;\n    if (ctx->pkey != NULL) {\n        provkey = evp_keymgmt_export_to_provider(ctx->pkey, exchange->keymgmt);\n        if (provkey == NULL) {\n            EVPerr(EVP_F_EVP_PKEY_DERIVE_INIT_EX, EVP_R_INITIALIZATION_ERROR);\n            goto err;\n        }\n    }\n    ctx->exchprovctx = exchange->newctx(ossl_provider_ctx(exchange->prov));\n    if (ctx->exchprovctx == NULL) {\n        EVPerr(EVP_F_EVP_PKEY_DERIVE_INIT_EX, EVP_R_INITIALIZATION_ERROR);\n        goto err;\n    }\n    ret = exchange->init(ctx->exchprovctx, provkey);\n    return ret ? 1 : 0;\n err:\n    ctx->operation = EVP_PKEY_OP_UNDEFINED;\n    return 0;\n legacy:\n    if (ctx == NULL || ctx->pmeth == NULL || ctx->pmeth->derive == NULL) {\n        EVPerr(EVP_F_EVP_PKEY_DERIVE_INIT_EX,\n               EVP_R_OPERATION_NOT_SUPPORTED_FOR_THIS_KEYTYPE);\n        return -2;\n    }\n    if (ctx->pmeth->derive_init == NULL)\n        return 1;\n    ret = ctx->pmeth->derive_init(ctx);\n    if (ret <= 0)\n        ctx->operation = EVP_PKEY_OP_UNDEFINED;\n    return ret;\n}', 'const char *OBJ_nid2sn(int n)\n{\n    ADDED_OBJ ad, *adp;\n    ASN1_OBJECT ob;\n    if ((n >= 0) && (n < NUM_NID)) {\n        if ((n != NID_undef) && (nid_objs[n].nid == NID_undef)) {\n            OBJerr(OBJ_F_OBJ_NID2SN, OBJ_R_UNKNOWN_NID);\n            return NULL;\n        }\n        return nid_objs[n].sn;\n    } else if (added == NULL)\n        return NULL;\n    else {\n        ad.type = ADDED_NID;\n        ad.obj = &ob;\n        ob.nid = n;\n        adp = lh_ADDED_OBJ_retrieve(added, &ad);\n        if (adp != NULL)\n            return adp->obj->sn;\n        else {\n            OBJerr(OBJ_F_OBJ_NID2SN, OBJ_R_UNKNOWN_NID);\n            return NULL;\n        }\n    }\n}']