DPP: Build bootstrapping key DER encoding using custom routine

While the OpenSSL version of i2d_EC_PUBKEY() seemed to be able to use
the POINT_CONVERSION_COMPRESSED setting on the EC key, that did not seem
to work with BoringSSL. Since this is not exactly robust design, replace
use of i2d_EC_PUBKEY() with a custom routine that enforces the DPP rules
on SubjectPublicKeyInfo (compressed format of the public key,
ecPublicKey OID, parameters present and indicating the curve by OID).

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
This commit is contained in:
Jouni Malinen 2017-11-18 12:19:43 +02:00 committed by Jouni Malinen
parent f2d27ef94c
commit 746c1792ac

View File

@ -9,6 +9,8 @@
#include "utils/includes.h" #include "utils/includes.h"
#include <openssl/opensslv.h> #include <openssl/opensslv.h>
#include <openssl/err.h> #include <openssl/err.h>
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
#include "utils/common.h" #include "utils/common.h"
#include "utils/base64.h" #include "utils/base64.h"
@ -1154,30 +1156,84 @@ static EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve,
} }
typedef struct {
/* AlgorithmIdentifier ecPublicKey with optional parameters present
* as an OID identifying the curve */
X509_ALGOR *alg;
/* Compressed format public key per ANSI X9.63 */
ASN1_BIT_STRING *pub_key;
} DPP_BOOTSTRAPPING_KEY;
ASN1_SEQUENCE(DPP_BOOTSTRAPPING_KEY) = {
ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, alg, X509_ALGOR),
ASN1_SIMPLE(DPP_BOOTSTRAPPING_KEY, pub_key, ASN1_BIT_STRING)
} ASN1_SEQUENCE_END(DPP_BOOTSTRAPPING_KEY);
IMPLEMENT_ASN1_FUNCTIONS(DPP_BOOTSTRAPPING_KEY);
static struct wpabuf * dpp_bootstrap_key_der(EVP_PKEY *key) static struct wpabuf * dpp_bootstrap_key_der(EVP_PKEY *key)
{ {
unsigned char *der = NULL; unsigned char *der = NULL;
int der_len; int der_len;
EC_KEY *eckey; EC_KEY *eckey;
struct wpabuf *ret; struct wpabuf *ret = NULL;
size_t len;
const EC_GROUP *group;
const EC_POINT *point;
BN_CTX *ctx;
DPP_BOOTSTRAPPING_KEY *bootstrap = NULL;
int nid;
/* Need to get the compressed form of the public key through EC_KEY, so ctx = BN_CTX_new();
* cannot use the simpler i2d_PUBKEY() here. */
eckey = EVP_PKEY_get1_EC_KEY(key); eckey = EVP_PKEY_get1_EC_KEY(key);
if (!eckey) if (!ctx || !eckey)
return NULL; goto fail;
EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED);
der_len = i2d_EC_PUBKEY(eckey, &der); group = EC_KEY_get0_group(eckey);
EC_KEY_free(eckey); point = EC_KEY_get0_public_key(eckey);
if (!group || !point)
goto fail;
nid = EC_GROUP_get_curve_name(group);
bootstrap = DPP_BOOTSTRAPPING_KEY_new();
if (!bootstrap ||
X509_ALGOR_set0(bootstrap->alg, OBJ_nid2obj(EVP_PKEY_EC),
V_ASN1_OBJECT, (void *) OBJ_nid2obj(nid)) != 1)
goto fail;
len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
NULL, 0, ctx);
if (len == 0)
goto fail;
der = OPENSSL_malloc(len);
if (!der)
goto fail;
len = EC_POINT_point2oct(group, point, POINT_CONVERSION_COMPRESSED,
der, len, ctx);
OPENSSL_free(bootstrap->pub_key->data);
bootstrap->pub_key->data = der;
der = NULL;
bootstrap->pub_key->length = len;
/* No unused bits */
bootstrap->pub_key->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07);
bootstrap->pub_key->flags |= ASN1_STRING_FLAG_BITS_LEFT;
der_len = i2d_DPP_BOOTSTRAPPING_KEY(bootstrap, &der);
if (der_len <= 0) { if (der_len <= 0) {
wpa_printf(MSG_ERROR, wpa_printf(MSG_ERROR,
"DDP: Failed to build DER encoded public key"); "DDP: Failed to build DER encoded public key");
OPENSSL_free(der); goto fail;
return NULL;
} }
ret = wpabuf_alloc_copy(der, der_len); ret = wpabuf_alloc_copy(der, der_len);
fail:
DPP_BOOTSTRAPPING_KEY_free(bootstrap);
OPENSSL_free(der); OPENSSL_free(der);
EC_KEY_free(eckey);
BN_CTX_free(ctx);
return ret; return ret;
} }