Re: decoder memory-management question

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux