I wrote: > I'm planning similar X25519 integration. That turned out to not take long (see attached) as a fork of the Ed25519 provider. Merging the providers would have taken slightly more work. I don't know how well OpenSSL scales with the number of providers. On Haswell, this bumps `openssl speed ecdhx25519` up from 21123.0 op/s to 29652.0 op/s, and produces even bigger speedups in key generation (not shown by `openssl speed`). This could also be tweaked to support batch key generation as in engntru and eng25519. Batch DH could be done with a separate thread. Caveats from my previous message apply. These providers could easily have serious problems. Some OpenSSL features that would help build confidence would include a much simpler provider API, positive and negative tests for the API, and a clear memory-management discipline. ---D. J. Bernstein
// D. J. Bernstein // 20240302 // SPDX-License-Identifier: LicenseRef-PD-hp OR CC0-1.0 OR 0BSD OR MIT-0 OR MIT #define provider_name "openssl_x25519_lib25519" #define provider_version "20240302" /* Basic requirements on the underlying DH library: - Must follow a SUPERCOP-style DH interface. Overall structure of this file: dhlib glue code at the top, then the painful part. The dhlib glue code wraps the DH library: - Sizes: - DHLIB_PKBYTES is the number of public-key bytes. - DHLIB_SKBYTES is the number of secret-key bytes. - DHLIB_SHAREDBYTES is the number of shared-secret bytes. - Data structure: - struct dhlib_key stores data[DHLIB_SKBYTES+DHLIB_PKBYTES], state. - state DHLIB_KEY_EMPTY: data is all 0. - state DHLIB_KEY_PK: data is zeros followed by public key. - state DHLIB_KEY_SK: data is secret key followed by public key. - DHLIB_KEY_EMPTY is guaranteed to be 0. - Functions: - dhlib_key_generate(&K): stores a new secret key in K. - dhlib_key_derive(shared,&peer,&K): derives secret shared with peer. - OpenSSL-style return values: 1 for success, 0 for failure. - Constants to interface with OpenSSL: - dhlib_pubkey_asn1_prefix is DER prefix for public keys - dhlib_algorithm_asn1 is DER encoding of just the system name - dhlib_algorithm_name is main command-line name for the system - dhlib_algorithm_names is name:altname1:altname2:... (see openssl/providers/implementations/include/prov/names.h) - dhlib_algorithm_nid is the OpenSSL NID for the signature system (as NID_...) */ #include <openssl/crypto.h> // to use OPENSSL_zalloc in the dhlib code #include <inttypes.h> // for SIZE_MAX, LLONG_MAX #include <string.h> // for memset #include <lib25519.h> // the wrapped library #define dhlib_algorithm_name "X25519" #define dhlib_algorithm_names "X25519:1.3.101.110" #define dhlib_algorithm_nid NID_X25519 static const unsigned char dhlib_pubkey_asn1_prefix[16] = { 0x30,0x2e, 0x02,0x01,0x00, 0x30,0x05,0x06,0x03,0x2b,0x65,0x6e, 0x04,0x22,0x04,0x20 } ; #define DHLIB_PKBYTES lib25519_dh_PUBLICKEYBYTES #define DHLIB_SKBYTES lib25519_dh_SECRETKEYBYTES #define DHLIB_SHAREDBYTES lib25519_dh_BYTES struct dhlib_key { unsigned char data[DHLIB_SKBYTES+DHLIB_PKBYTES]; unsigned char state; } ; #define DHLIB_KEY_EMPTY 0 #define DHLIB_KEY_PK 1 #define DHLIB_KEY_SK 2 static int dhlib_key_generate(struct dhlib_key *K) { if (!K) return 0; lib25519_dh_keypair(K->data+DHLIB_SKBYTES,K->data); K->state = DHLIB_KEY_SK; return 1; } static int dhlib_key_derive(unsigned char *shared,const struct dhlib_key *peer,const struct dhlib_key *K) { if (!K) return 0; if (K->state != DHLIB_KEY_SK) return 0; if (!peer) return 0; if (!peer->state) return 0; if (!shared) return 0; lib25519_dh(shared,peer->data+DHLIB_SKBYTES,K->data); return 1; } // ----- and now the painful part begins #include <openssl/core.h> #include <openssl/core_dispatch.h> #include <openssl/core_object.h> #include <openssl/core_names.h> #include <openssl/params.h> #include <openssl/param_build.h> #include <openssl/provider.h> #include <openssl/bio.h> #include <openssl/asn1.h> #include <openssl/pem.h> #include <openssl/x509.h> extern int asn1_d2i_read_bio(BIO *,BUF_MEM **); // XXX: sigh // various objects below have no parameters static const OSSL_PARAM no_params[] = { OSSL_PARAM_END } ; #define PROVIDER "provider=" provider_name // ----- encoder and decoder // no reason to allocate an extra layer // so pointer to encoder/decoder context is just provider-context pointer static void *coder_newctx(void *provctx) { return provctx; } static void coder_freectx(void *ctx) { ; // nothing to do } static int encode(void *ctx,OSSL_CORE_BIO *out,const void *obj_raw,const OSSL_PARAM obj_abstract[],int selection,OSSL_PASSPHRASE_CALLBACK *cb,void *cbarg,int flagpem) { // XXX: probably easier to just precompute constant strings for all four cases // XXX: is it possible to skip the PEM part of the encoder? OSSL_LIB_CTX *provider_context = ctx; const struct dhlib_key *K = obj_raw; BIO *bio = 0; int ok = 0; if (obj_abstract) return 0; if (!K) return 0; bio = BIO_new_from_core_bio(provider_context,out); if (!bio) return 0; do { if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) { ASN1_OCTET_STRING bytes; unsigned char *der = 0; int derlen; PKCS8_PRIV_KEY_INFO *sk_pkcs8; if (K->state != DHLIB_KEY_SK) break; bytes.data = (void *) K->data; bytes.length = DHLIB_SKBYTES+DHLIB_PKBYTES; bytes.flags = 0; // XXX: should this be trying to use secure_zalloc instead? derlen = i2d_ASN1_OCTET_STRING(&bytes,&der); if (derlen < 0) break; do { sk_pkcs8 = PKCS8_PRIV_KEY_INFO_new(); if (!sk_pkcs8) break; do { if (!PKCS8_pkey_set0(sk_pkcs8,OBJ_nid2obj(dhlib_algorithm_nid),0,V_ASN1_UNDEF,0,der,derlen)) break; der = 0; // since sk_pkcs8 has taken responsibility if (flagpem) { if (!PEM_write_bio_PKCS8_PRIV_KEY_INFO(bio,sk_pkcs8)) break; } else { if (!i2d_PKCS8_PRIV_KEY_INFO_bio(bio,sk_pkcs8)) break; } ok = 1; } while(0); PKCS8_PRIV_KEY_INFO_free(sk_pkcs8); } while(0); if (der) OPENSSL_clear_free(der,derlen); break; } if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { unsigned char *pk_copy = OPENSSL_zalloc(DHLIB_PKBYTES); if (!pk_copy) break; do { X509_PUBKEY *pk_x509 = X509_PUBKEY_new(); if (!pk_x509) break; do { if (!K->state) break; memcpy(pk_copy,K->data+DHLIB_SKBYTES,DHLIB_PKBYTES); if (!X509_PUBKEY_set0_param(pk_x509,OBJ_nid2obj(dhlib_algorithm_nid),V_ASN1_UNDEF,0,pk_copy,DHLIB_PKBYTES)) break; pk_copy = 0; // since pk_x509 has taken responsibility if (flagpem) { if (!PEM_write_bio_X509_PUBKEY(bio,pk_x509)) break; } else { if (!i2d_X509_PUBKEY_bio(bio,pk_x509)) break; } ok = 1; } while(0); X509_PUBKEY_free(pk_x509); break; } while(0); if (pk_copy) OPENSSL_clear_free(pk_copy,DHLIB_PKBYTES); } } while(0); BIO_free(bio); return ok; } static int encode_DER(void *ctx,OSSL_CORE_BIO *out,const void *obj_raw,const OSSL_PARAM obj_abstract[],int selection,OSSL_PASSPHRASE_CALLBACK *cb,void *cbarg) { return encode(ctx,out,obj_raw,obj_abstract,selection,cb,cbarg,0); } static int encode_PEM(void *ctx,OSSL_CORE_BIO *out,const void *obj_raw,const OSSL_PARAM obj_abstract[],int selection,OSSL_PASSPHRASE_CALLBACK *cb,void *cbarg) { return encode(ctx,out,obj_raw,obj_abstract,selection,cb,cbarg,1); } static int decode_DER(void *ctx,OSSL_CORE_BIO *in,int selection,OSSL_CALLBACK *data_cb,void *data_cbarg,OSSL_PASSPHRASE_CALLBACK *cb,void *cbarg) { OSSL_LIB_CTX *provider_context = ctx; BIO *bio = 0; int ok = 1; if (!in) return 1; bio = BIO_new_from_core_bio(provider_context,in); if (!bio) return 1; do { int flagpub; for (flagpub = 0;flagpub < 2;++flagpub) { if (!data_cb) break; if (flagpub) { if (!(selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY)) continue; } else { if (!(selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY)) continue; } BUF_MEM *mem = 0; long xlen = 0; const unsigned char *x2 = 0; PKCS8_PRIV_KEY_INFO *sk_pkcs8 = 0; if (asn1_d2i_read_bio(bio,&mem) < 0) continue; x2 = (void *) mem->data; xlen = mem->length; do { if (flagpub) { // maybe could do something like this: pk_x509 = d2i_X509_PUBKEY(0,&x2,xlen); // but clearly easier to just decode by hand if (xlen != DHLIB_PKBYTES + sizeof dhlib_pubkey_asn1_prefix) break; if (CRYPTO_memcmp(x2,dhlib_pubkey_asn1_prefix,sizeof dhlib_pubkey_asn1_prefix)) break; } else { // XXX: consider decoding directly in this case too sk_pkcs8 = d2i_PKCS8_PRIV_KEY_INFO(0,&x2,xlen); if (!sk_pkcs8) break; } do { const unsigned char *y = 0; int ylen = 0; const X509_ALGOR *algorithmid = 0; ASN1_OCTET_STRING *bytes = 0; if (!flagpub) { if (!PKCS8_pkey_get0(0,&y,&ylen,&algorithmid,sk_pkcs8)) break; if (OBJ_obj2nid(algorithmid->algorithm) != dhlib_algorithm_nid) break; bytes = d2i_ASN1_OCTET_STRING(0,&y,ylen); if (!bytes) break; } do { struct dhlib_key *K = 0; if (!flagpub) if (ASN1_STRING_length(bytes) != DHLIB_SKBYTES+DHLIB_PKBYTES) break; K = OPENSSL_secure_zalloc(sizeof(struct dhlib_key)); if (!K) break; do { int pkey = OSSL_OBJECT_PKEY; OSSL_PARAM params[4]; if (flagpub) { memcpy(K->data+DHLIB_SKBYTES,x2+xlen-DHLIB_PKBYTES,DHLIB_PKBYTES); K->state = DHLIB_KEY_PK; } else { memcpy(K->data,ASN1_STRING_get0_data(bytes),DHLIB_SKBYTES+DHLIB_PKBYTES); K->state = DHLIB_KEY_SK; } params[0] = OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE,&pkey); params[1] = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE,dhlib_algorithm_name,0); params[2] = OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_REFERENCE,&K,sizeof(K)); params[3] = OSSL_PARAM_construct_end(); if (data_cb) ok = data_cb(params,data_cbarg); data_cb = 0; // make sure we do not call it twice } while(0); // K should be 0 if and only if callback took control of key if (K) OPENSSL_secure_clear_free(K,sizeof(struct dhlib_key)); } while(0); if (!flagpub) ASN1_OCTET_STRING_free(bytes); } while(0); if (!flagpub) PKCS8_PRIV_KEY_INFO_free(sk_pkcs8); } while(0); BUF_MEM_free(mem); } } while(0); BIO_free(bio); return ok; } static const OSSL_DISPATCH encode_DER_functions[] = { { OSSL_FUNC_ENCODER_NEWCTX, (void(*)(void)) coder_newctx }, { OSSL_FUNC_ENCODER_FREECTX, (void(*)(void)) coder_freectx }, { OSSL_FUNC_ENCODER_ENCODE, (void(*)(void)) encode_DER }, { 0, 0 }, } ; static const OSSL_DISPATCH encode_PEM_functions[] = { { OSSL_FUNC_ENCODER_NEWCTX, (void(*)(void)) coder_newctx }, { OSSL_FUNC_ENCODER_FREECTX, (void(*)(void)) coder_freectx }, { OSSL_FUNC_ENCODER_ENCODE, (void(*)(void)) encode_PEM }, { 0, 0 }, } ; static const OSSL_DISPATCH decode_DER_functions[] = { { OSSL_FUNC_DECODER_NEWCTX, (void(*)(void)) coder_newctx }, { OSSL_FUNC_DECODER_FREECTX, (void(*)(void)) coder_freectx }, { OSSL_FUNC_DECODER_DECODE, (void(*)(void)) decode_DER }, { 0, 0 }, } ; static const OSSL_ALGORITHM provider_encoder[] = { { dhlib_algorithm_names,PROVIDER ",output=der,structure=PrivateKeyInfo",encode_DER_functions }, { dhlib_algorithm_names,PROVIDER ",output=pem,structure=PrivateKeyInfo",encode_PEM_functions }, { dhlib_algorithm_names,PROVIDER ",output=der,structure=SubjectPublicKeyInfo",encode_DER_functions }, { dhlib_algorithm_names,PROVIDER ",output=pem,structure=SubjectPublicKeyInfo",encode_PEM_functions }, { 0, 0, 0 }, }; static const OSSL_ALGORITHM provider_decoder[] = { { dhlib_algorithm_names,PROVIDER ",input=der,structure=PrivateKeyInfo",decode_DER_functions }, { dhlib_algorithm_names,PROVIDER ",input=der,structure=SubjectPublicKeyInfo",decode_DER_functions }, { 0, 0, 0 }, }; // ----- keygen // as in encoder/decoder, no reason to allocate an extra layer // so pointer to key-generator context is just provider-context pointer static void *key_gen_init(void *provctx,int selection,const OSSL_PARAM params[]) { return provctx; } static void key_gen_cleanup(void *genctx) { ; // nothing to do } static void *key_new(void *provctx) { return OPENSSL_secure_zalloc(sizeof(struct dhlib_key)); } static void key_free(void *keydata) { OPENSSL_secure_clear_free(keydata,sizeof(struct dhlib_key)); } static int key_gen_set_params(void *genctx,const OSSL_PARAM params[]) { return 1; } static const OSSL_PARAM *key_gen_settable_params(void *genctx,void *provctx) { return no_params; } static void *key_gen(void *genctx,OSSL_CALLBACK *cb,void *cbarg) { struct dhlib_key *K = key_new(genctx); if (!K) return 0; if (!dhlib_key_generate(K)) { key_free(K); return 0; } return K; } static void *key_load(const void *reference,size_t reference_sz) { struct dhlib_key *K = 0; if (!reference) return 0; if (reference_sz != sizeof(K)) return 0; K = *(struct dhlib_key **) reference; *(struct dhlib_key **) reference = 0; return K; } static const OSSL_PARAM keygen_params[] = { OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_MAX_SIZE,0,0), OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_DEFAULT_DIGEST,0,0), OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_MANDATORY_DIGEST,0,0), OSSL_PARAM_END } ; static const OSSL_PARAM *key_gettable_params(void *provctx) { return keygen_params; } static int key_get_params(void *keydata,OSSL_PARAM params[]) { OSSL_PARAM *p = 0; // need MAX_SIZE for openssl pkeyutl -verify p = OSSL_PARAM_locate(params,OSSL_PKEY_PARAM_MAX_SIZE); if (p && !OSSL_PARAM_set_int(p,DHLIB_SHAREDBYTES)) return 0; p = OSSL_PARAM_locate(params,OSSL_PKEY_PARAM_DEFAULT_DIGEST); if (p && !OSSL_PARAM_set_utf8_string(p,SN_undef)) return 0; p = OSSL_PARAM_locate(params,OSSL_PKEY_PARAM_MANDATORY_DIGEST); if (p && !OSSL_PARAM_set_utf8_string(p,SN_undef)) return 0; return 1; } static const OSSL_PARAM *key_settable_params(void *provctx) { return no_params; } static int key_set_params(void *keydata, const OSSL_PARAM params[]) { return 1; } static int key_has(const void *keydata,int selection) { const struct dhlib_key *K = keydata; int result = 1; if (!K) return 0; if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) result &= (K->state != 0); if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) result &= (K->state == DHLIB_KEY_SK); return result; } static int key_match(const void *keydata1,const void *keydata2,int selection) { const struct dhlib_key *K1 = keydata1; const struct dhlib_key *K2 = keydata2; if (!K1) return 0; if (!K2) return 0; if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) if (K1->state && K2->state) if (!CRYPTO_memcmp(K1->data+DHLIB_SKBYTES,K2->data+DHLIB_SKBYTES,DHLIB_PKBYTES)) return 1; if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) if ((K1->state == DHLIB_KEY_SK) && (K2->state == DHLIB_KEY_SK)) if (!CRYPTO_memcmp(K1->data,K2->data,DHLIB_SKBYTES)) return 1; return 0; } static int key_import(void *keydata,int selection,const OSSL_PARAM params[]) { struct dhlib_key *K = keydata; if (!K) return 0; if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { const OSSL_PARAM *p = OSSL_PARAM_locate_const(params,OSSL_PKEY_PARAM_PUB_KEY); if (p) { size_t len = 0; void *ptr = K->data+DHLIB_SKBYTES; memset(K,0,sizeof(struct dhlib_key)); if (!OSSL_PARAM_get_octet_string(p,&ptr,DHLIB_PKBYTES,&len)) return 0; if (len != DHLIB_PKBYTES) return 0; K->state = DHLIB_KEY_PK; } } if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) { const OSSL_PARAM *p = OSSL_PARAM_locate_const(params,OSSL_PKEY_PARAM_PRIV_KEY); if (p) { size_t len = 0; void *ptr = K->data; memset(K,0,sizeof(struct dhlib_key)); if (!OSSL_PARAM_get_octet_string(p,&ptr,DHLIB_SKBYTES+DHLIB_PKBYTES,&len)) return 0; if (len != DHLIB_SKBYTES) return 0; K->state = DHLIB_KEY_SK; } } return 1; } static int key_export(void *keydata,int selection,OSSL_CALLBACK *param_cb,void *cbarg) { struct dhlib_key *K = keydata; #define KEY_EXPORT_PARAMS_MAX 3 OSSL_PARAM params[KEY_EXPORT_PARAMS_MAX]; int paramspos = 0; if (!K) return 0; if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) if (K->state) { if (paramspos >= KEY_EXPORT_PARAMS_MAX) return 0; params[paramspos++] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY,K->data+DHLIB_SKBYTES,DHLIB_PKBYTES); } if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) if (K->state == DHLIB_KEY_SK) { if (paramspos >= KEY_EXPORT_PARAMS_MAX) return 0; params[paramspos++] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PRIV_KEY,K->data,DHLIB_SKBYTES); } if (paramspos >= KEY_EXPORT_PARAMS_MAX) return 0; params[paramspos++] = OSSL_PARAM_construct_end(); return param_cb(params,cbarg); } static const OSSL_PARAM params_pub_and_priv[] = { OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY,0,0), OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY,0,0), OSSL_PARAM_END } ; static const OSSL_PARAM *key_import_export_types(int selection) { if (selection & OSSL_KEYMGMT_SELECT_KEYPAIR) return params_pub_and_priv; // maybe in principle should narrow further by pub-vs-priv selection // but examples in openssl do not do that return 0; } static const OSSL_DISPATCH key_functions[] = { { OSSL_FUNC_KEYMGMT_NEW, (void(*)(void)) key_new }, { OSSL_FUNC_KEYMGMT_FREE, (void(*)(void)) key_free }, { OSSL_FUNC_KEYMGMT_GEN_INIT, (void(*)(void)) key_gen_init }, { OSSL_FUNC_KEYMGMT_GEN_SET_PARAMS, (void(*)(void)) key_gen_set_params }, { OSSL_FUNC_KEYMGMT_GEN_SETTABLE_PARAMS, (void(*)(void)) key_gen_settable_params }, { OSSL_FUNC_KEYMGMT_GEN, (void(*)(void)) key_gen }, { OSSL_FUNC_KEYMGMT_GEN_CLEANUP, (void(*)(void)) key_gen_cleanup }, { OSSL_FUNC_KEYMGMT_LOAD, (void(*)(void)) key_load }, { OSSL_FUNC_KEYMGMT_GETTABLE_PARAMS, (void(*)(void)) key_gettable_params }, { OSSL_FUNC_KEYMGMT_GET_PARAMS, (void(*)(void)) key_get_params }, { OSSL_FUNC_KEYMGMT_SETTABLE_PARAMS, (void(*)(void)) key_settable_params }, { OSSL_FUNC_KEYMGMT_SET_PARAMS, (void(*)(void)) key_set_params }, { OSSL_FUNC_KEYMGMT_HAS, (void(*)(void)) key_has }, { OSSL_FUNC_KEYMGMT_MATCH, (void(*)(void)) key_match }, { OSSL_FUNC_KEYMGMT_IMPORT, (void(*)(void)) key_import }, { OSSL_FUNC_KEYMGMT_EXPORT, (void(*)(void)) key_export }, { OSSL_FUNC_KEYMGMT_IMPORT_TYPES, (void(*)(void)) key_import_export_types }, { OSSL_FUNC_KEYMGMT_EXPORT_TYPES, (void(*)(void)) key_import_export_types }, { 0, 0 }, } ; static const OSSL_ALGORITHM provider_keygen[] = { { dhlib_algorithm_names,PROVIDER,key_functions }, { 0, 0, 0 }, }; // ----- shared-secret derivation struct dh_context { struct dhlib_key peer; struct dhlib_key key; } ; static void *dh_new(void *provctx) { return OPENSSL_secure_zalloc(sizeof(struct dh_context)); } static void dh_free(void *ctx) { OPENSSL_secure_clear_free(ctx,sizeof(struct dh_context)); } static int dh_copykey(void *ctx,void *provkey,const OSSL_PARAM params[]) { struct dh_context *D = ctx; if (!D) return 0; if (!provkey) return 1; // XXX: where is it documented that provkey can legitimately be 0? // this occurs in "reinit" during, e.g., openssl speed memcpy(&D->key,provkey,sizeof(struct dhlib_key)); return 1; } static int dh_copypeer(void *ctx,void *provkey) { struct dh_context *D = ctx; if (!D) return 0; if (!provkey) return 1; memcpy(&D->peer,provkey,sizeof(struct dhlib_key)); return 1; } static int dh_derive(void *ctx,unsigned char *secret,size_t *secretlen,size_t outlen) { struct dh_context *D = ctx; if (!D) return 0; if (!secret) { *secretlen = DHLIB_SHAREDBYTES; return 1; } if (outlen < DHLIB_SHAREDBYTES) return 0; if (!dhlib_key_derive(secret,&D->peer,&D->key)) return 0; *secretlen = DHLIB_SHAREDBYTES; return 1; } static const OSSL_PARAM *dh_gettable_params(void *provctx) { return no_params; } static int dh_get_params(void *ctx,OSSL_PARAM params[]) { return 1; } static const OSSL_DISPATCH dh_functions[] = { { OSSL_FUNC_KEYEXCH_NEWCTX, (void(*)(void)) dh_new }, { OSSL_FUNC_KEYEXCH_FREECTX, (void(*)(void)) dh_free }, { OSSL_FUNC_KEYEXCH_INIT, (void(*)(void)) dh_copykey }, { OSSL_FUNC_KEYEXCH_SET_PEER, (void(*)(void)) dh_copypeer }, { OSSL_FUNC_KEYEXCH_DERIVE, (void(*)(void)) dh_derive }, { OSSL_FUNC_KEYEXCH_GETTABLE_CTX_PARAMS, (void(*)(void)) dh_gettable_params }, { OSSL_FUNC_KEYEXCH_GET_CTX_PARAMS, (void(*)(void)) dh_get_params }, { 0, 0 }, }; static const OSSL_ALGORITHM provider_dh[] = { { dhlib_algorithm_names,PROVIDER,dh_functions }, { 0, 0, 0 }, }; // ----- top-level provider functions static const OSSL_ALGORITHM *provider_get_algorithms(void *provctx,int operation_id,int *no_store) { *no_store = 0; // ok for openssl to store results if (operation_id == OSSL_OP_ENCODER) return provider_encoder; if (operation_id == OSSL_OP_DECODER) return provider_decoder; if (operation_id == OSSL_OP_KEYMGMT) return provider_keygen; if (operation_id == OSSL_OP_KEYEXCH) return provider_dh; return 0; } static const OSSL_PARAM provider_params_list[] = { OSSL_PARAM_DEFN(OSSL_PROV_PARAM_NAME,OSSL_PARAM_UTF8_PTR,0,0), OSSL_PARAM_DEFN(OSSL_PROV_PARAM_VERSION,OSSL_PARAM_UTF8_PTR,0,0), OSSL_PARAM_DEFN(OSSL_PROV_PARAM_STATUS,OSSL_PARAM_INTEGER,0,0), OSSL_PARAM_END, } ; static const OSSL_PARAM *provider_gettable_params(void) { return provider_params_list; } // used by, e.g., openssl list -providers static int provider_get_params(void *provctx,OSSL_PARAM params[]) { OSSL_PARAM *p = 0; p = OSSL_PARAM_locate(params,OSSL_PROV_PARAM_NAME); if (p && !OSSL_PARAM_set_utf8_ptr(p,provider_name)) return 0; p = OSSL_PARAM_locate(params,OSSL_PROV_PARAM_VERSION); if (p && !OSSL_PARAM_set_utf8_ptr(p,provider_version)) return 0; p = OSSL_PARAM_locate(params,OSSL_PROV_PARAM_STATUS); if (p && !OSSL_PARAM_set_int(p,1)) return 0; // 1 means provider is running return 1; } static void provider_teardown(void *provctx) { OSSL_LIB_CTX_free(provctx); } static const OSSL_DISPATCH provider_functions[] = { { OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void(*)(void)) provider_get_algorithms }, { OSSL_FUNC_PROVIDER_GETTABLE_PARAMS, (void(*)(void)) provider_gettable_params }, { OSSL_FUNC_PROVIDER_GET_PARAMS, (void(*)(void)) provider_get_params }, { OSSL_FUNC_PROVIDER_TEARDOWN, (void(*)(void)) provider_teardown }, { 0, 0 }, }; int OSSL_provider_init(const OSSL_CORE_HANDLE *handle,const OSSL_DISPATCH *in,const OSSL_DISPATCH **out,void **provctx) { OSSL_LIB_CTX *provider_context = OSSL_LIB_CTX_new_child(handle,in); if (!provider_context) return 0; *out = provider_functions; *provctx = provider_context; return 1; }
Attachment:
test2.sh
Description: Bourne shell script
Attachment:
signature.asc
Description: PGP signature