Make OpenSSL an hcrypto backend proper

This adds a new backend for libhcrypto: the OpenSSL backend.

Now libhcrypto has these backends:

 - hcrypto itself (i.e., the algorithms coded in lib/hcrypto)
 - Common Crypto (OS X)
 - PKCS#11 (specifically for Solaris, but not Solaris-specific)
 - Windows CNG (Windows)
 - OpenSSL (generic)

The ./configure --with-openssl=... option no longer disables the use of
hcrypto.  Instead it enables the use of OpenSSL as a (and the default)
backend in libhcrypto.  The libhcrypto framework is now always used.

OpenSSL should no longer be used directly within Heimdal, except in the
OpenSSL hcrypto backend itself, and files where elliptic curve (EC)
crypto is needed.

Because libhcrypto's EC support is incomplete, we can only use OpenSSL
for EC.  Currently that means separating all EC-using code so that it
does not use hcrypto, thus the libhx509/hxtool and PKINIT EC code has
been moved out of the files it used to be in.
This commit is contained in:
Nicolas Williams
2016-04-13 12:44:58 -05:00
parent 9df88205ba
commit 490337f4f9
60 changed files with 2206 additions and 976 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright (c) 2003 - 2007 Kungliga Tekniska Högskolan
* Copyright (c) 2003 - 2016 Kungliga Tekniska Högskolan
* (Royal Institute of Technology, Stockholm, Sweden).
* All rights reserved.
*
@@ -58,27 +58,6 @@ struct krb5_pk_cert {
hx509_cert cert;
};
struct krb5_pk_init_ctx_data {
struct krb5_pk_identity *id;
enum { USE_RSA, USE_DH, USE_ECDH } keyex;
union {
DH *dh;
#ifdef HAVE_OPENSSL
EC_KEY *eckey;
#endif
} u;
krb5_data *clientDHNonce;
struct krb5_dh_moduli **m;
hx509_peer_info peer;
enum krb5_pk_type type;
unsigned int require_binding:1;
unsigned int require_eku:1;
unsigned int require_krbtgt_otherName:1;
unsigned int require_hostname_match:1;
unsigned int trustedCertifiers:1;
unsigned int anonymous:1;
};
static void
pk_copy_error(krb5_context context,
hx509_context hx509ctx,
@@ -533,74 +512,14 @@ build_auth_pack(krb5_context context,
return ret;
if (size != dhbuf.length)
krb5_abortx(context, "asn1 internal error");
a->clientPublicValue->subjectPublicKey.length = dhbuf.length * 8;
a->clientPublicValue->subjectPublicKey.data = dhbuf.data;
} else if (ctx->keyex == USE_ECDH) {
#ifdef HAVE_OPENSSL
ECParameters ecp;
unsigned char *p;
int xlen;
/* copy in public key, XXX find the best curve that the server support or use the clients curve if possible */
ecp.element = choice_ECParameters_namedCurve;
ret = der_copy_oid(&asn1_oid_id_ec_group_secp256r1,
&ecp.u.namedCurve);
if (ret)
return ret;
ALLOC(a->clientPublicValue->algorithm.parameters, 1);
if (a->clientPublicValue->algorithm.parameters == NULL) {
free_ECParameters(&ecp);
return ENOMEM;
}
ASN1_MALLOC_ENCODE(ECParameters, p, xlen, &ecp, &size, ret);
free_ECParameters(&ecp);
if (ret)
return ret;
if ((int)size != xlen)
krb5_abortx(context, "asn1 internal error");
a->clientPublicValue->algorithm.parameters->data = p;
a->clientPublicValue->algorithm.parameters->length = size;
/* copy in public key */
ret = der_copy_oid(&asn1_oid_id_ecPublicKey,
&a->clientPublicValue->algorithm.algorithm);
if (ret)
return ret;
ctx->u.eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
if (ctx->u.eckey == NULL)
return ENOMEM;
ret = EC_KEY_generate_key(ctx->u.eckey);
if (ret != 1)
return EINVAL;
/* encode onto dhkey */
xlen = i2o_ECPublicKey(ctx->u.eckey, NULL);
if (xlen <= 0)
abort();
dhbuf.data = malloc(xlen);
if (dhbuf.data == NULL)
abort();
dhbuf.length = xlen;
p = dhbuf.data;
xlen = i2o_ECPublicKey(ctx->u.eckey, &p);
if (xlen <= 0)
abort();
/* XXX verify that this is right with RFC3279 */
#else
return EINVAL;
#endif
ret = _krb5_build_authpack_subjectPK_EC(context, ctx, a);
if (ret)
return ret;
} else
krb5_abortx(context, "internal error");
a->clientPublicValue->subjectPublicKey.length = dhbuf.length * 8;
a->clientPublicValue->subjectPublicKey.data = dhbuf.data;
}
{
@@ -1443,51 +1362,11 @@ pk_rd_pa_reply_dh(krb5_context context,
}
} else {
#ifdef HAVE_OPENSSL
const EC_GROUP *group;
EC_KEY *public = NULL;
group = EC_KEY_get0_group(ctx->u.eckey);
public = EC_KEY_new();
if (public == NULL) {
ret = ENOMEM;
goto out;
}
if (EC_KEY_set_group(public, group) != 1) {
EC_KEY_free(public);
ret = ENOMEM;
goto out;
}
if (o2i_ECPublicKey(&public, &p, size) == NULL) {
EC_KEY_free(public);
ret = KRB5KRB_ERR_GENERIC;
krb5_set_error_message(context, ret,
N_("PKINIT: Can't parse ECDH public key", ""));
goto out;
}
size = (EC_GROUP_get_degree(group) + 7) / 8;
dh_gen_key = malloc(size);
if (dh_gen_key == NULL) {
EC_KEY_free(public);
ret = krb5_enomem(context);
goto out;
}
dh_gen_keylen = ECDH_compute_key(dh_gen_key, size,
EC_KEY_get0_public_key(public), ctx->u.eckey, NULL);
EC_KEY_free(public);
if (dh_gen_keylen == -1) {
ret = KRB5KRB_ERR_GENERIC;
dh_gen_keylen = 0;
krb5_set_error_message(context, ret,
N_("PKINIT: Can't compute ECDH public key", ""));
goto out;
}
#else
ret = EINVAL;
#endif
ret = _krb5_pk_rd_pa_reply_ecdh_compute_key(context, ctx, p,
size, &dh_gen_key,
&dh_gen_keylen);
if (ret)
goto out;
}
if (dh_gen_keylen <= 0) {
@@ -2309,10 +2188,8 @@ _krb5_get_init_creds_opt_free_pkinit(krb5_get_init_creds_opt *opt)
case USE_RSA:
break;
case USE_ECDH:
#ifdef HAVE_OPENSSL
if (ctx->u.eckey)
EC_KEY_free(ctx->u.eckey);
#endif
_krb5_pk_eckey_free(ctx->u.eckey);
break;
}
if (ctx->id) {