]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
DPP: Move configurator backup into a separate source code file
authorJouni Malinen <jouni@codeaurora.org>
Sun, 10 May 2020 22:30:13 +0000 (01:30 +0300)
committerJouni Malinen <j@w1.fi>
Mon, 11 May 2020 14:26:11 +0000 (17:26 +0300)
This continues splitting dpp.c into smaller pieces.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
hostapd/Android.mk
hostapd/Makefile
src/common/dpp.c
src/common/dpp_backup.c [new file with mode: 0644]
src/common/dpp_i.h
tests/fuzzing/dpp-uri/Makefile
wpa_supplicant/Android.mk
wpa_supplicant/Makefile

index eaa566e60c171355901dd2ac90db08fb0ebd0d69..5cda74885bbd6835cec69a2049ca8bf74002fe12 100644 (file)
@@ -538,6 +538,7 @@ ifdef CONFIG_DPP
 L_CFLAGS += -DCONFIG_DPP
 OBJS += src/common/dpp.c
 OBJS += src/common/dpp_auth.c
+OBJS += src/common/dpp_backup.c
 OBJS += src/common/dpp_crypto.c
 OBJS += src/common/dpp_pkex.c
 OBJS += src/common/dpp_reconfig.c
index c6725b006a7691cc2c1d9ca2f663be337aa91e75..b2d782aac9a3b570fe02bb9fe846ffaeb565f647 100644 (file)
@@ -569,6 +569,7 @@ ifdef CONFIG_DPP
 CFLAGS += -DCONFIG_DPP
 OBJS += ../src/common/dpp.o
 OBJS += ../src/common/dpp_auth.o
+OBJS += ../src/common/dpp_backup.o
 OBJS += ../src/common/dpp_crypto.o
 OBJS += ../src/common/dpp_pkex.o
 OBJS += ../src/common/dpp_reconfig.o
index e9f1a35cb6e90a9afbd3aad3a9041c46d3b70c93..870364a2929e270112c86237911d6ebe914d5d45 100644 (file)
@@ -24,7 +24,6 @@
 #include "crypto/random.h"
 #include "crypto/aes.h"
 #include "crypto/aes_siv.h"
-#include "tls/asn1.h"
 #include "drivers/driver.h"
 #include "dpp.h"
 #include "dpp_i.h"
@@ -1274,20 +1273,6 @@ fail:
 }
 
 
-static void dpp_free_asymmetric_key(struct dpp_asymmetric_key *key)
-{
-       while (key) {
-               struct dpp_asymmetric_key *next = key->next;
-
-               EVP_PKEY_free(key->csign);
-               str_clear_free(key->config_template);
-               str_clear_free(key->connector_template);
-               os_free(key);
-               key = next;
-       }
-}
-
-
 void dpp_auth_deinit(struct dpp_authentication *auth)
 {
        unsigned int i;
@@ -1312,7 +1297,9 @@ void dpp_auth_deinit(struct dpp_authentication *auth)
                os_free(conf->connector);
                wpabuf_free(conf->c_sign_key);
        }
+#ifdef CONFIG_DPP2
        dpp_free_asymmetric_key(auth->conf_key_pkg);
+#endif /* CONFIG_DPP2 */
        wpabuf_free(auth->net_access_key);
        dpp_bootstrap_info_free(auth->tmp_own_bi);
 #ifdef CONFIG_TESTING_OPTIONS
@@ -1655,488 +1642,6 @@ dpp_build_conf_obj(struct dpp_authentication *auth, enum dpp_netrole netrole,
 }
 
 
-#ifdef CONFIG_DPP2
-
-static struct wpabuf * dpp_build_conf_params(void)
-{
-       struct wpabuf *buf;
-       size_t len;
-       /* TODO: proper template values */
-       const char *conf_template = "{\"wi-fi_tech\":\"infra\",\"discovery\":{\"ssid\":\"test\"},\"cred\":{\"akm\":\"dpp\"}}";
-       const char *connector_template = NULL;
-
-       len = 100 + os_strlen(conf_template);
-       if (connector_template)
-               len += os_strlen(connector_template);
-       buf = wpabuf_alloc(len);
-       if (!buf)
-               return NULL;
-
-       /*
-        * DPPConfigurationParameters ::= SEQUENCE {
-        *    configurationTemplate     UTF8String,
-        *    connectorTemplate         UTF8String OPTIONAL}
-        */
-
-       asn1_put_utf8string(buf, conf_template);
-       if (connector_template)
-               asn1_put_utf8string(buf, connector_template);
-       return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
-}
-
-
-static struct wpabuf * dpp_build_attribute(void)
-{
-       struct wpabuf *conf_params, *attr;
-
-       /*
-        * aa-DPPConfigurationParameters ATTRIBUTE ::=
-        * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
-        *
-        * Attribute ::= SEQUENCE {
-        *    type OBJECT IDENTIFIER,
-        *    values SET SIZE(1..MAX) OF Type
-        */
-       conf_params = dpp_build_conf_params();
-       conf_params = asn1_encaps(conf_params, ASN1_CLASS_UNIVERSAL,
-                                 ASN1_TAG_SET);
-       if (!conf_params)
-               return NULL;
-
-       attr = wpabuf_alloc(100 + wpabuf_len(conf_params));
-       if (!attr) {
-               wpabuf_clear_free(conf_params);
-               return NULL;
-       }
-
-       asn1_put_oid(attr, &asn1_dpp_config_params_oid);
-       wpabuf_put_buf(attr, conf_params);
-       wpabuf_clear_free(conf_params);
-
-       return asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
-}
-
-
-static struct wpabuf * dpp_build_key_alg(const struct dpp_curve_params *curve)
-{
-       const struct asn1_oid *oid;
-       struct wpabuf *params, *res;
-
-       switch (curve->ike_group) {
-       case 19:
-               oid = &asn1_prime256v1_oid;
-               break;
-       case 20:
-               oid = &asn1_secp384r1_oid;
-               break;
-       case 21:
-               oid = &asn1_secp521r1_oid;
-               break;
-       case 28:
-               oid = &asn1_brainpoolP256r1_oid;
-               break;
-       case 29:
-               oid = &asn1_brainpoolP384r1_oid;
-               break;
-       case 30:
-               oid = &asn1_brainpoolP512r1_oid;
-               break;
-       default:
-               return NULL;
-       }
-
-       params = wpabuf_alloc(20);
-       if (!params)
-               return NULL;
-       asn1_put_oid(params, oid); /* namedCurve */
-
-       res = asn1_build_alg_id(&asn1_ec_public_key_oid, params);
-       wpabuf_free(params);
-       return res;
-}
-
-
-static struct wpabuf * dpp_build_key_pkg(struct dpp_authentication *auth)
-{
-       struct wpabuf *key = NULL, *attr, *alg, *priv_key = NULL;
-       EC_KEY *eckey;
-       unsigned char *der = NULL;
-       int der_len;
-
-       eckey = EVP_PKEY_get0_EC_KEY(auth->conf->csign);
-       if (!eckey)
-               return NULL;
-
-       EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY);
-       der_len = i2d_ECPrivateKey(eckey, &der);
-       if (der_len > 0)
-               priv_key = wpabuf_alloc_copy(der, der_len);
-       OPENSSL_free(der);
-
-       alg = dpp_build_key_alg(auth->conf->curve);
-
-       /* Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } */
-       attr = dpp_build_attribute();
-       attr = asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SET);
-       if (!priv_key || !attr || !alg)
-               goto fail;
-
-       /*
-        * OneAsymmetricKey ::= SEQUENCE {
-        *    version                   Version,
-        *    privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
-        *    privateKey                PrivateKey,
-        *    attributes                [0] Attributes OPTIONAL,
-        *    ...,
-        *    [[2: publicKey            [1] BIT STRING OPTIONAL ]],
-        *    ...
-        * }
-        */
-
-       key = wpabuf_alloc(100 + wpabuf_len(alg) + wpabuf_len(priv_key) +
-                          wpabuf_len(attr));
-       if (!key)
-               goto fail;
-
-       asn1_put_integer(key, 1); /* version = v2(1) */
-
-       /* PrivateKeyAlgorithmIdentifier */
-       wpabuf_put_buf(key, alg);
-
-       /* PrivateKey ::= OCTET STRING */
-       asn1_put_octet_string(key, priv_key);
-
-       /* [0] Attributes OPTIONAL */
-       asn1_put_hdr(key, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0, wpabuf_len(attr));
-       wpabuf_put_buf(key, attr);
-
-fail:
-       wpabuf_clear_free(attr);
-       wpabuf_clear_free(priv_key);
-       wpabuf_free(alg);
-
-       /*
-        * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
-        *
-        * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
-        *
-        * OneAsymmetricKey ::= SEQUENCE
-        */
-       return asn1_encaps(asn1_encaps(key,
-                                      ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE),
-                          ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
-}
-
-
-static struct wpabuf * dpp_build_pbkdf2_alg_id(const struct wpabuf *salt,
-                                              size_t hash_len)
-{
-       struct wpabuf *params = NULL, *buf = NULL, *prf = NULL;
-       const struct asn1_oid *oid;
-
-       /*
-        * PBKDF2-params ::= SEQUENCE {
-        *    salt CHOICE {
-        *       specified OCTET STRING,
-        *       otherSource AlgorithmIdentifier}
-        *    iterationCount INTEGER (1..MAX),
-        *    keyLength INTEGER (1..MAX),
-        *    prf AlgorithmIdentifier}
-        *
-        * salt is an 64 octet value, iterationCount is 1000, keyLength is based
-        * on Configurator signing key length, prf is
-        * id-hmacWithSHA{256,384,512} based on Configurator signing key.
-        */
-
-       if (hash_len == 32)
-               oid = &asn1_pbkdf2_hmac_sha256_oid;
-       else if (hash_len == 48)
-               oid = &asn1_pbkdf2_hmac_sha384_oid;
-       else if (hash_len == 64)
-               oid = &asn1_pbkdf2_hmac_sha512_oid;
-       else
-               goto fail;
-       prf = asn1_build_alg_id(oid, NULL);
-       if (!prf)
-               goto fail;
-       params = wpabuf_alloc(100 + wpabuf_len(salt) + wpabuf_len(prf));
-       if (!params)
-               goto fail;
-       asn1_put_octet_string(params, salt); /* salt.specified */
-       asn1_put_integer(params, 1000); /* iterationCount */
-       asn1_put_integer(params, hash_len); /* keyLength */
-       wpabuf_put_buf(params, prf);
-       params = asn1_encaps(params, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
-       if (!params)
-               goto fail;
-       buf = asn1_build_alg_id(&asn1_pbkdf2_oid, params);
-fail:
-       wpabuf_free(params);
-       wpabuf_free(prf);
-       return buf;
-}
-
-
-static struct wpabuf *
-dpp_build_pw_recipient_info(struct dpp_authentication *auth, size_t hash_len,
-                           const struct wpabuf *cont_enc_key)
-{
-       struct wpabuf *pwri = NULL, *enc_key = NULL, *key_der_alg = NULL,
-               *key_enc_alg = NULL, *salt;
-       u8 kek[DPP_MAX_HASH_LEN];
-       const u8 *key;
-       size_t key_len;
-
-       salt = wpabuf_alloc(64);
-       if (!salt || os_get_random(wpabuf_put(salt, 64), 64) < 0)
-               goto fail;
-       wpa_hexdump_buf(MSG_DEBUG, "DPP: PBKDF2 salt", salt);
-
-       /* TODO: For initial testing, use ke as the key. Replace this with a
-        * new key once that has been defined. */
-       key = auth->ke;
-       key_len = auth->curve->hash_len;
-       wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
-
-       if (dpp_pbkdf2(hash_len, key, key_len, wpabuf_head(salt), 64, 1000,
-                      kek, hash_len)) {
-               wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed");
-               goto fail;
-       }
-       wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2",
-                       kek, hash_len);
-
-       enc_key = wpabuf_alloc(hash_len + AES_BLOCK_SIZE);
-       if (!enc_key ||
-           aes_siv_encrypt(kek, hash_len, wpabuf_head(cont_enc_key),
-                           wpabuf_len(cont_enc_key), 0, NULL, NULL,
-                           wpabuf_put(enc_key, hash_len + AES_BLOCK_SIZE)) < 0)
-               goto fail;
-       wpa_hexdump_buf(MSG_DEBUG, "DPP: encryptedKey", enc_key);
-
-       /*
-        * PasswordRecipientInfo ::= SEQUENCE {
-        *    version                   CMSVersion,
-        *    keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
-        *    keyEncryptionAlgorithm    KeyEncryptionAlgorithmIdentifier,
-        *    encryptedKey              EncryptedKey}
-        *
-        * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
-        * parameters contains PBKDF2-params SEQUENCE.
-        */
-
-       key_der_alg = dpp_build_pbkdf2_alg_id(salt, hash_len);
-       key_enc_alg = asn1_build_alg_id(&asn1_aes_siv_cmac_aead_256_oid, NULL);
-       if (!key_der_alg || !key_enc_alg)
-               goto fail;
-       pwri = wpabuf_alloc(100 + wpabuf_len(key_der_alg) +
-                           wpabuf_len(key_enc_alg) + wpabuf_len(enc_key));
-       if (!pwri)
-               goto fail;
-
-       /* version = 0 */
-       asn1_put_integer(pwri, 0);
-
-       /* [0] KeyDerivationAlgorithmIdentifier */
-       asn1_put_hdr(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0,
-                    wpabuf_len(key_der_alg));
-       wpabuf_put_buf(pwri, key_der_alg);
-
-       /* KeyEncryptionAlgorithmIdentifier */
-       wpabuf_put_buf(pwri, key_enc_alg);
-
-       /* EncryptedKey ::= OCTET STRING */
-       asn1_put_octet_string(pwri, enc_key);
-
-fail:
-       wpabuf_clear_free(key_der_alg);
-       wpabuf_free(key_enc_alg);
-       wpabuf_free(enc_key);
-       wpabuf_free(salt);
-       forced_memzero(kek, sizeof(kek));
-       return asn1_encaps(pwri, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
-}
-
-
-static struct wpabuf *
-dpp_build_recipient_info(struct dpp_authentication *auth, size_t hash_len,
-                        const struct wpabuf *cont_enc_key)
-{
-       struct wpabuf *pwri;
-
-       /*
-        * RecipientInfo ::= CHOICE {
-        *    ktri              KeyTransRecipientInfo,
-        *    kari      [1]     KeyAgreeRecipientInfo,
-        *    kekri     [2]     KEKRecipientInfo,
-        *    pwri      [3]     PasswordRecipientInfo,
-        *    ori       [4]     OtherRecipientInfo}
-        *
-        * Shall always use the pwri CHOICE.
-        */
-
-       pwri = dpp_build_pw_recipient_info(auth, hash_len, cont_enc_key);
-       return asn1_encaps(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 3);
-}
-
-
-static struct wpabuf *
-dpp_build_enc_cont_info(struct dpp_authentication *auth, size_t hash_len,
-                       const struct wpabuf *cont_enc_key)
-{
-       struct wpabuf *key_pkg, *enc_cont_info = NULL, *enc_cont = NULL,
-               *enc_alg;
-       const struct asn1_oid *oid;
-       size_t enc_cont_len;
-
-       /*
-        * EncryptedContentInfo ::= SEQUENCE {
-        *    contentType                       ContentType,
-        *    contentEncryptionAlgorithm  ContentEncryptionAlgorithmIdentifier,
-        *    encryptedContent  [0] IMPLICIT    EncryptedContent OPTIONAL}
-        */
-
-       if (hash_len == 32)
-               oid = &asn1_aes_siv_cmac_aead_256_oid;
-       else if (hash_len == 48)
-               oid = &asn1_aes_siv_cmac_aead_384_oid;
-       else if (hash_len == 64)
-               oid = &asn1_aes_siv_cmac_aead_512_oid;
-       else
-               return NULL;
-
-       key_pkg = dpp_build_key_pkg(auth);
-       enc_alg = asn1_build_alg_id(oid, NULL);
-       if (!key_pkg || !enc_alg)
-               goto fail;
-
-       wpa_hexdump_buf_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage",
-                           key_pkg);
-
-       enc_cont_len = wpabuf_len(key_pkg) + AES_BLOCK_SIZE;
-       enc_cont = wpabuf_alloc(enc_cont_len);
-       if (!enc_cont ||
-           aes_siv_encrypt(wpabuf_head(cont_enc_key), wpabuf_len(cont_enc_key),
-                           wpabuf_head(key_pkg), wpabuf_len(key_pkg),
-                           0, NULL, NULL,
-                           wpabuf_put(enc_cont, enc_cont_len)) < 0)
-               goto fail;
-
-       enc_cont_info = wpabuf_alloc(100 + wpabuf_len(enc_alg) +
-                                    wpabuf_len(enc_cont));
-       if (!enc_cont_info)
-               goto fail;
-
-       /* ContentType ::= OBJECT IDENTIFIER */
-       asn1_put_oid(enc_cont_info, &asn1_dpp_asymmetric_key_package_oid);
-
-       /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
-       wpabuf_put_buf(enc_cont_info, enc_alg);
-
-       /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
-        * EncryptedContent ::= OCTET STRING */
-       asn1_put_hdr(enc_cont_info, ASN1_CLASS_CONTEXT_SPECIFIC, 0, 0,
-                    wpabuf_len(enc_cont));
-       wpabuf_put_buf(enc_cont_info, enc_cont);
-
-fail:
-       wpabuf_clear_free(key_pkg);
-       wpabuf_free(enc_cont);
-       wpabuf_free(enc_alg);
-       return enc_cont_info;
-}
-
-
-static struct wpabuf * dpp_gen_random(size_t len)
-{
-       struct wpabuf *key;
-
-       key = wpabuf_alloc(len);
-       if (!key || os_get_random(wpabuf_put(key, len), len) < 0) {
-               wpabuf_free(key);
-               key = NULL;
-       }
-       wpa_hexdump_buf_key(MSG_DEBUG, "DPP: content-encryption key", key);
-       return key;
-}
-
-
-static struct wpabuf * dpp_build_enveloped_data(struct dpp_authentication *auth)
-{
-       struct wpabuf *env = NULL;
-       struct wpabuf *recipient_info = NULL, *enc_cont_info = NULL;
-       struct wpabuf *cont_enc_key = NULL;
-       size_t hash_len;
-
-       if (!auth->conf) {
-               wpa_printf(MSG_DEBUG,
-                          "DPP: No Configurator instance selected for the session - cannot build DPPEnvelopedData");
-               return NULL;
-       }
-
-       if (!auth->provision_configurator) {
-               wpa_printf(MSG_DEBUG,
-                          "DPP: Configurator provisioning not allowed");
-               return NULL;
-       }
-
-       wpa_printf(MSG_DEBUG, "DPP: Building DPPEnvelopedData");
-
-       hash_len = auth->conf->curve->hash_len;
-       cont_enc_key = dpp_gen_random(hash_len);
-       if (!cont_enc_key)
-               goto fail;
-       recipient_info = dpp_build_recipient_info(auth, hash_len, cont_enc_key);
-       enc_cont_info = dpp_build_enc_cont_info(auth, hash_len, cont_enc_key);
-       if (!recipient_info || !enc_cont_info)
-               goto fail;
-
-       env = wpabuf_alloc(wpabuf_len(recipient_info) +
-                          wpabuf_len(enc_cont_info) +
-                          100);
-       if (!env)
-               goto fail;
-
-       /*
-        * DPPEnvelopedData ::= EnvelopedData
-        *
-        * EnvelopedData ::= SEQUENCE {
-        *    version                   CMSVersion,
-        *    originatorInfo    [0]     IMPLICIT OriginatorInfo OPTIONAL,
-        *    recipientInfos            RecipientInfos,
-        *    encryptedContentInfo      EncryptedContentInfo,
-        *    unprotectedAttrs  [1] IMPLICIT    UnprotectedAttributes OPTIONAL}
-        *
-        * For DPP, version is 3, both originatorInfo and
-        * unprotectedAttrs are omitted, and recipientInfos contains a single
-        * RecipientInfo.
-        */
-
-       /* EnvelopedData.version = 3 */
-       asn1_put_integer(env, 3);
-
-       /* RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo */
-       asn1_put_set(env, recipient_info);
-
-       /* EncryptedContentInfo ::= SEQUENCE */
-       asn1_put_sequence(env, enc_cont_info);
-
-       env = asn1_encaps(env, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
-       wpa_hexdump_buf(MSG_MSGDUMP, "DPP: DPPEnvelopedData", env);
-out:
-       wpabuf_clear_free(cont_enc_key);
-       wpabuf_clear_free(recipient_info);
-       wpabuf_free(enc_cont_info);
-       return env;
-fail:
-       wpabuf_free(env);
-       env = NULL;
-       goto out;
-}
-
-#endif /* CONFIG_DPP2 */
-
-
 static struct wpabuf *
 dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce,
                    u16 e_nonce_len, enum dpp_netrole netrole)
@@ -3123,709 +2628,6 @@ fail:
 }
 
 
-#ifdef CONFIG_DPP2
-
-struct dpp_enveloped_data {
-       const u8 *enc_cont;
-       size_t enc_cont_len;
-       const u8 *enc_key;
-       size_t enc_key_len;
-       const u8 *salt;
-       size_t pbkdf2_key_len;
-       size_t prf_hash_len;
-};
-
-
-static int dpp_parse_recipient_infos(const u8 *pos, size_t len,
-                                    struct dpp_enveloped_data *data)
-{
-       struct asn1_hdr hdr;
-       const u8 *end = pos + len;
-       const u8 *next, *e_end;
-       struct asn1_oid oid;
-       int val;
-       const u8 *params;
-       size_t params_len;
-
-       wpa_hexdump(MSG_MSGDUMP, "DPP: RecipientInfos", pos, len);
-
-       /*
-        * RecipientInfo ::= CHOICE {
-        *    ktri              KeyTransRecipientInfo,
-        *    kari      [1]     KeyAgreeRecipientInfo,
-        *    kekri     [2]     KEKRecipientInfo,
-        *    pwri      [3]     PasswordRecipientInfo,
-        *    ori       [4]     OtherRecipientInfo}
-        *
-        * Shall always use the pwri CHOICE.
-        */
-
-       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-           hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 3) {
-               wpa_printf(MSG_DEBUG,
-                          "DPP: Expected CHOICE [3] (pwri) - found class %d tag 0x%x",
-                          hdr.class, hdr.tag);
-               return -1;
-       }
-       wpa_hexdump(MSG_MSGDUMP, "DPP: PasswordRecipientInfo",
-                   hdr.payload, hdr.length);
-       pos = hdr.payload;
-       end = pos + hdr.length;
-
-       /*
-        * PasswordRecipientInfo ::= SEQUENCE {
-        *    version                   CMSVersion,
-        *    keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
-        *    keyEncryptionAlgorithm    KeyEncryptionAlgorithmIdentifier,
-        *    encryptedKey              EncryptedKey}
-        *
-        * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
-        * parameters contains PBKDF2-params SEQUENCE.
-        */
-
-       if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0)
-               return -1;
-       pos = hdr.payload;
-
-       if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
-               return -1;
-       if (val != 0) {
-               wpa_printf(MSG_DEBUG, "DPP: pwri.version != 0");
-               return -1;
-       }
-
-       wpa_hexdump(MSG_MSGDUMP, "DPP: Remaining PasswordRecipientInfo after version",
-                   pos, end - pos);
-
-       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-           hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
-               wpa_printf(MSG_DEBUG,
-                          "DPP: Expected keyDerivationAlgorithm [0] - found class %d tag 0x%x",
-                          hdr.class, hdr.tag);
-               return -1;
-       }
-       pos = hdr.payload;
-       e_end = pos + hdr.length;
-
-       /* KeyDerivationAlgorithmIdentifier ::= AlgorithmIdentifier */
-       if (asn1_get_alg_id(pos, e_end - pos, &oid, &params, &params_len,
-                           &next) < 0)
-               return -1;
-       if (!asn1_oid_equal(&oid, &asn1_pbkdf2_oid)) {
-               char buf[80];
-
-               asn1_oid_to_str(&oid, buf, sizeof(buf));
-               wpa_printf(MSG_DEBUG,
-                          "DPP: Unexpected KeyDerivationAlgorithmIdentifier %s",
-                          buf);
-               return -1;
-       }
-
-       /*
-        * PBKDF2-params ::= SEQUENCE {
-        *    salt CHOICE {
-        *       specified OCTET STRING,
-        *       otherSource AlgorithmIdentifier}
-        *    iterationCount INTEGER (1..MAX),
-        *    keyLength INTEGER (1..MAX),
-        *    prf AlgorithmIdentifier}
-        *
-        * salt is an 64 octet value, iterationCount is 1000, keyLength is based
-        * on Configurator signing key length, prf is
-        * id-hmacWithSHA{256,384,512} based on Configurator signing key.
-        */
-       if (!params ||
-           asn1_get_sequence(params, params_len, &hdr, &e_end) < 0)
-               return -1;
-       pos = hdr.payload;
-
-       if (asn1_get_next(pos, e_end - pos, &hdr) < 0 ||
-           hdr.class != ASN1_CLASS_UNIVERSAL ||
-           hdr.tag != ASN1_TAG_OCTETSTRING) {
-               wpa_printf(MSG_DEBUG,
-                          "DPP: Expected OCTETSTRING (salt.specified) - found class %d tag 0x%x",
-                          hdr.class, hdr.tag);
-               return -1;
-       }
-       wpa_hexdump(MSG_MSGDUMP, "DPP: salt.specified",
-                   hdr.payload, hdr.length);
-       if (hdr.length != 64) {
-               wpa_printf(MSG_DEBUG, "DPP: Unexpected salt length %u",
-                          hdr.length);
-               return -1;
-       }
-       data->salt = hdr.payload;
-       pos = hdr.payload + hdr.length;
-
-       if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0)
-               return -1;
-       if (val != 1000) {
-               wpa_printf(MSG_DEBUG, "DPP: Unexpected iterationCount %d", val);
-               return -1;
-       }
-
-       if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0)
-               return -1;
-       if (val != 32 && val != 48 && val != 64) {
-               wpa_printf(MSG_DEBUG, "DPP: Unexpected keyLength %d", val);
-               return -1;
-       }
-       data->pbkdf2_key_len = val;
-
-       if (asn1_get_sequence(pos, e_end - pos, &hdr, NULL) < 0 ||
-           asn1_get_oid(hdr.payload, hdr.length, &oid, &pos) < 0) {
-               wpa_printf(MSG_DEBUG, "DPP: Could not parse prf");
-               return -1;
-       }
-       if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha256_oid)) {
-               data->prf_hash_len = 32;
-       } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha384_oid)) {
-               data->prf_hash_len = 48;
-       } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha512_oid)) {
-               data->prf_hash_len = 64;
-       } else {
-               char buf[80];
-
-               asn1_oid_to_str(&oid, buf, sizeof(buf));
-               wpa_printf(MSG_DEBUG, "DPP: Unexpected PBKDF2-params.prf %s",
-                          buf);
-               return -1;
-       }
-
-       pos = next;
-
-       /* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier
-        *
-        * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
-        *
-        * id-alg-AES-SIV-CMAC-aed-256, id-alg-AES-SIV-CMAC-aed-384, or
-        * id-alg-AES-SIV-CMAC-aed-512. */
-       if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0)
-               return -1;
-       if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) &&
-           !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) &&
-           !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) {
-               char buf[80];
-
-               asn1_oid_to_str(&oid, buf, sizeof(buf));
-               wpa_printf(MSG_DEBUG,
-                          "DPP: Unexpected KeyEncryptionAlgorithmIdentifier %s",
-                          buf);
-               return -1;
-       }
-
-       /*
-        * encryptedKey EncryptedKey
-        *
-        * EncryptedKey ::= OCTET STRING
-        */
-       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-           hdr.class != ASN1_CLASS_UNIVERSAL ||
-           hdr.tag != ASN1_TAG_OCTETSTRING) {
-               wpa_printf(MSG_DEBUG,
-                          "DPP: Expected OCTETSTRING (pwri.encryptedKey) - found class %d tag 0x%x",
-                          hdr.class, hdr.tag);
-               return -1;
-       }
-       wpa_hexdump(MSG_MSGDUMP, "DPP: pwri.encryptedKey",
-                   hdr.payload, hdr.length);
-       data->enc_key = hdr.payload;
-       data->enc_key_len = hdr.length;
-
-       return 0;
-}
-
-
-static int dpp_parse_encrypted_content_info(const u8 *pos, const u8 *end,
-                                           struct dpp_enveloped_data *data)
-{
-       struct asn1_hdr hdr;
-       struct asn1_oid oid;
-
-       /*
-        * EncryptedContentInfo ::= SEQUENCE {
-        *    contentType                       ContentType,
-        *    contentEncryptionAlgorithm  ContentEncryptionAlgorithmIdentifier,
-        *    encryptedContent  [0] IMPLICIT    EncryptedContent OPTIONAL}
-        */
-       if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
-               return -1;
-       wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContentInfo",
-                   hdr.payload, hdr.length);
-       if (pos < end) {
-               wpa_hexdump(MSG_DEBUG,
-                           "DPP: Unexpected extra data after EncryptedContentInfo",
-                           pos, end - pos);
-               return -1;
-       }
-
-       end = pos;
-       pos = hdr.payload;
-
-       /* ContentType ::= OBJECT IDENTIFIER */
-       if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) {
-               wpa_printf(MSG_DEBUG, "DPP: Could not parse ContentType");
-               return -1;
-       }
-       if (!asn1_oid_equal(&oid, &asn1_dpp_asymmetric_key_package_oid)) {
-               char buf[80];
-
-               asn1_oid_to_str(&oid, buf, sizeof(buf));
-               wpa_printf(MSG_DEBUG, "DPP: Unexpected ContentType %s", buf);
-               return -1;
-       }
-
-       /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
-       if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0)
-               return -1;
-       if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) &&
-           !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) &&
-           !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) {
-               char buf[80];
-
-               asn1_oid_to_str(&oid, buf, sizeof(buf));
-               wpa_printf(MSG_DEBUG,
-                          "DPP: Unexpected ContentEncryptionAlgorithmIdentifier %s",
-                          buf);
-               return -1;
-       }
-       /* ignore optional parameters */
-
-       /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
-        * EncryptedContent ::= OCTET STRING */
-       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-           hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
-               wpa_printf(MSG_DEBUG,
-                          "DPP: Expected [0] IMPLICIT (EncryptedContent) - found class %d tag 0x%x",
-                          hdr.class, hdr.tag);
-               return -1;
-       }
-       wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContent",
-                   hdr.payload, hdr.length);
-       data->enc_cont = hdr.payload;
-       data->enc_cont_len = hdr.length;
-       return 0;
-}
-
-
-static int dpp_parse_enveloped_data(const u8 *env_data, size_t env_data_len,
-                                   struct dpp_enveloped_data *data)
-{
-       struct asn1_hdr hdr;
-       const u8 *pos, *end;
-       int val;
-
-       os_memset(data, 0, sizeof(*data));
-
-       /*
-        * DPPEnvelopedData ::= EnvelopedData
-        *
-        * EnvelopedData ::= SEQUENCE {
-        *    version                   CMSVersion,
-        *    originatorInfo    [0]     IMPLICIT OriginatorInfo OPTIONAL,
-        *    recipientInfos            RecipientInfos,
-        *    encryptedContentInfo      EncryptedContentInfo,
-        *    unprotectedAttrs  [1] IMPLICIT    UnprotectedAttributes OPTIONAL}
-        *
-        * CMSVersion ::= INTEGER
-        *
-        * RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo
-        *
-        * For DPP, version is 3, both originatorInfo and
-        * unprotectedAttrs are omitted, and recipientInfos contains a single
-        * RecipientInfo.
-        */
-       if (asn1_get_sequence(env_data, env_data_len, &hdr, &end) < 0)
-               return -1;
-       pos = hdr.payload;
-       if (end < env_data + env_data_len) {
-               wpa_hexdump(MSG_DEBUG,
-                           "DPP: Unexpected extra data after DPPEnvelopedData",
-                           end, env_data + env_data_len - end);
-               return -1;
-       }
-
-       if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
-               return -1;
-       if (val != 3) {
-               wpa_printf(MSG_DEBUG, "DPP: EnvelopedData.version != 3");
-               return -1;
-       }
-
-       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-           hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
-               wpa_printf(MSG_DEBUG,
-                          "DPP: Expected SET (RecipientInfos) - found class %d tag 0x%x",
-                          hdr.class, hdr.tag);
-               return -1;
-       }
-
-       if (dpp_parse_recipient_infos(hdr.payload, hdr.length, data) < 0)
-               return -1;
-       return dpp_parse_encrypted_content_info(hdr.payload + hdr.length, end,
-                                               data);
-}
-
-
-static struct dpp_asymmetric_key *
-dpp_parse_one_asymmetric_key(const u8 *buf, size_t len)
-{
-       struct asn1_hdr hdr;
-       const u8 *pos = buf, *end = buf + len, *next;
-       int val;
-       const u8 *params;
-       size_t params_len;
-       struct asn1_oid oid;
-       char txt[80];
-       struct dpp_asymmetric_key *key;
-       EC_KEY *eckey;
-
-       wpa_hexdump_key(MSG_MSGDUMP, "DPP: OneAsymmetricKey", buf, len);
-
-       key = os_zalloc(sizeof(*key));
-       if (!key)
-               return NULL;
-
-       /*
-        * OneAsymmetricKey ::= SEQUENCE {
-        *    version                   Version,
-        *    privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
-        *    privateKey                PrivateKey,
-        *    attributes                [0] Attributes OPTIONAL,
-        *    ...,
-        *    [[2: publicKey            [1] BIT STRING OPTIONAL ]],
-        *    ...
-        * }
-        */
-       if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0)
-               goto fail;
-       pos = hdr.payload;
-
-       /* Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) */
-       if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
-               goto fail;
-       if (val != 1) {
-               wpa_printf(MSG_DEBUG,
-                          "DPP: Unsupported DPPAsymmetricKeyPackage version %d",
-                          val);
-               goto fail;
-       }
-
-       /* PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier */
-       if (asn1_get_alg_id(pos, end - pos, &oid, &params, &params_len,
-                           &pos) < 0)
-               goto fail;
-       if (!asn1_oid_equal(&oid, &asn1_ec_public_key_oid)) {
-               asn1_oid_to_str(&oid, txt, sizeof(txt));
-               wpa_printf(MSG_DEBUG,
-                          "DPP: Unsupported PrivateKeyAlgorithmIdentifier %s",
-                          txt);
-               goto fail;
-       }
-       wpa_hexdump(MSG_MSGDUMP, "DPP: PrivateKeyAlgorithmIdentifier params",
-                   params, params_len);
-       /*
-        * ECParameters ::= CHOICE {
-        *    namedCurve        OBJECT IDENTIFIER
-        *    -- implicitCurve  NULL
-        *    -- specifiedCurve SpecifiedECDomain}
-        */
-       if (!params || asn1_get_oid(params, params_len, &oid, &next) < 0) {
-               wpa_printf(MSG_DEBUG,
-                          "DPP: Could not parse ECParameters.namedCurve");
-               goto fail;
-       }
-       asn1_oid_to_str(&oid, txt, sizeof(txt));
-       wpa_printf(MSG_MSGDUMP, "DPP: namedCurve %s", txt);
-       /* Assume the curve is identified within ECPrivateKey, so that this
-        * separate indication is not really needed. */
-
-       /*
-        * PrivateKey ::= OCTET STRING
-        *    (Contains DER encoding of ECPrivateKey)
-        */
-       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-           hdr.class != ASN1_CLASS_UNIVERSAL ||
-           hdr.tag != ASN1_TAG_OCTETSTRING) {
-               wpa_printf(MSG_DEBUG,
-                          "DPP: Expected OCTETSTRING (PrivateKey) - found class %d tag 0x%x",
-                          hdr.class, hdr.tag);
-               goto fail;
-       }
-       wpa_hexdump_key(MSG_MSGDUMP, "DPP: PrivateKey",
-                       hdr.payload, hdr.length);
-       pos = hdr.payload + hdr.length;
-       eckey = d2i_ECPrivateKey(NULL, &hdr.payload, hdr.length);
-       if (!eckey) {
-               wpa_printf(MSG_INFO,
-                          "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
-                          ERR_error_string(ERR_get_error(), NULL));
-               goto fail;
-       }
-       key->csign = EVP_PKEY_new();
-       if (!key->csign || EVP_PKEY_assign_EC_KEY(key->csign, eckey) != 1) {
-               EC_KEY_free(eckey);
-               goto fail;
-       }
-       if (wpa_debug_show_keys)
-               dpp_debug_print_key("DPP: Received c-sign-key", key->csign);
-
-       /*
-        * Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } }
-        *
-        * Exactly one instance of type Attribute in OneAsymmetricKey.
-        */
-       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-           hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
-               wpa_printf(MSG_DEBUG,
-                          "DPP: Expected [0] Attributes - found class %d tag 0x%x",
-                          hdr.class, hdr.tag);
-               goto fail;
-       }
-       wpa_hexdump_key(MSG_MSGDUMP, "DPP: Attributes",
-                       hdr.payload, hdr.length);
-       if (hdr.payload + hdr.length < end) {
-               wpa_hexdump_key(MSG_MSGDUMP,
-                               "DPP: Ignore additional data at the end of OneAsymmetricKey",
-                               hdr.payload + hdr.length,
-                               end - (hdr.payload + hdr.length));
-       }
-       pos = hdr.payload;
-       end = hdr.payload + hdr.length;
-
-       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-           hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
-               wpa_printf(MSG_DEBUG,
-                          "DPP: Expected SET (Attributes) - found class %d tag 0x%x",
-                          hdr.class, hdr.tag);
-               goto fail;
-       }
-       if (hdr.payload + hdr.length < end) {
-               wpa_hexdump_key(MSG_MSGDUMP,
-                               "DPP: Ignore additional data at the end of OneAsymmetricKey (after SET)",
-                               hdr.payload + hdr.length,
-                               end - (hdr.payload + hdr.length));
-       }
-       pos = hdr.payload;
-       end = hdr.payload + hdr.length;
-
-       /*
-        * OneAsymmetricKeyAttributes ATTRIBUTE ::= {
-        *    aa-DPPConfigurationParameters,
-        *    ... -- For local profiles
-        * }
-        *
-        * aa-DPPConfigurationParameters ATTRIBUTE ::=
-        * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
-        *
-        * Attribute ::= SEQUENCE {
-        *    type OBJECT IDENTIFIER,
-        *    values SET SIZE(1..MAX) OF Type
-        *
-        * Exactly one instance of ATTRIBUTE in attrValues.
-        */
-       if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
-               goto fail;
-       if (pos < end) {
-               wpa_hexdump_key(MSG_MSGDUMP,
-                               "DPP: Ignore additional data at the end of ATTRIBUTE",
-                               pos, end - pos);
-       }
-       end = pos;
-       pos = hdr.payload;
-
-       if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0)
-               goto fail;
-       if (!asn1_oid_equal(&oid, &asn1_dpp_config_params_oid)) {
-               asn1_oid_to_str(&oid, txt, sizeof(txt));
-               wpa_printf(MSG_DEBUG,
-                          "DPP: Unexpected Attribute identifier %s", txt);
-               goto fail;
-       }
-
-       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-           hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
-               wpa_printf(MSG_DEBUG,
-                          "DPP: Expected SET (Attribute) - found class %d tag 0x%x",
-                          hdr.class, hdr.tag);
-               goto fail;
-       }
-       pos = hdr.payload;
-       end = hdr.payload + hdr.length;
-
-       /*
-        * DPPConfigurationParameters ::= SEQUENCE {
-        *    configurationTemplate     UTF8String,
-        *    connectorTemplate         UTF8String OPTIONAL}
-        */
-
-       wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPConfigurationParameters",
-                       pos, end - pos);
-       if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
-               goto fail;
-       if (pos < end) {
-               wpa_hexdump_key(MSG_MSGDUMP,
-                               "DPP: Ignore additional data after DPPConfigurationParameters",
-                               pos, end - pos);
-       }
-       end = pos;
-       pos = hdr.payload;
-
-       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-           hdr.class != ASN1_CLASS_UNIVERSAL ||
-           hdr.tag != ASN1_TAG_UTF8STRING) {
-               wpa_printf(MSG_DEBUG,
-                          "DPP: Expected UTF8STRING (configurationTemplate) - found class %d tag 0x%x",
-                          hdr.class, hdr.tag);
-               goto fail;
-       }
-       wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: configurationTemplate",
-                             hdr.payload, hdr.length);
-       key->config_template = os_zalloc(hdr.length + 1);
-       if (!key->config_template)
-               goto fail;
-       os_memcpy(key->config_template, hdr.payload, hdr.length);
-
-       pos = hdr.payload + hdr.length;
-
-       if (pos < end) {
-               if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
-                   hdr.class != ASN1_CLASS_UNIVERSAL ||
-                   hdr.tag != ASN1_TAG_UTF8STRING) {
-                       wpa_printf(MSG_DEBUG,
-                                  "DPP: Expected UTF8STRING (connectorTemplate) - found class %d tag 0x%x",
-                                  hdr.class, hdr.tag);
-                       goto fail;
-               }
-               wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: connectorTemplate",
-                                     hdr.payload, hdr.length);
-               key->connector_template = os_zalloc(hdr.length + 1);
-               if (!key->connector_template)
-                       goto fail;
-               os_memcpy(key->connector_template, hdr.payload, hdr.length);
-       }
-
-       return key;
-fail:
-       wpa_printf(MSG_DEBUG, "DPP: Failed to parse OneAsymmetricKey");
-       dpp_free_asymmetric_key(key);
-       return NULL;
-}
-
-
-static struct dpp_asymmetric_key *
-dpp_parse_dpp_asymmetric_key_package(const u8 *key_pkg, size_t key_pkg_len)
-{
-       struct asn1_hdr hdr;
-       const u8 *pos = key_pkg, *end = key_pkg + key_pkg_len;
-       struct dpp_asymmetric_key *first = NULL, *last = NULL, *key;
-
-       wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage",
-                       key_pkg, key_pkg_len);
-
-       /*
-        * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
-        *
-        * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
-        */
-       while (pos < end) {
-               if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0 ||
-                   !(key = dpp_parse_one_asymmetric_key(hdr.payload,
-                                                        hdr.length))) {
-                       dpp_free_asymmetric_key(first);
-                       return NULL;
-               }
-               if (!last) {
-                       first = last = key;
-               } else {
-                       last->next = key;
-                       last = key;
-               }
-       }
-
-       return first;
-}
-
-
-static int dpp_conf_resp_env_data(struct dpp_authentication *auth,
-                                 const u8 *env_data, size_t env_data_len)
-{
-       const u8 *key;
-       size_t key_len;
-       u8 kek[DPP_MAX_HASH_LEN];
-       u8 cont_encr_key[DPP_MAX_HASH_LEN];
-       size_t cont_encr_key_len;
-       int res;
-       u8 *key_pkg;
-       size_t key_pkg_len;
-       struct dpp_enveloped_data data;
-       struct dpp_asymmetric_key *keys;
-
-       wpa_hexdump(MSG_DEBUG, "DPP: DPPEnvelopedData", env_data, env_data_len);
-
-       if (dpp_parse_enveloped_data(env_data, env_data_len, &data) < 0)
-               return -1;
-
-       /* TODO: For initial testing, use ke as the key. Replace this with a
-        * new key once that has been defined. */
-       key = auth->ke;
-       key_len = auth->curve->hash_len;
-       wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
-
-       if (dpp_pbkdf2(data.prf_hash_len, key, key_len, data.salt, 64, 1000,
-                      kek, data.pbkdf2_key_len)) {
-               wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed");
-               return -1;
-       }
-       wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2",
-                       kek, data.pbkdf2_key_len);
-
-       if (data.enc_key_len < AES_BLOCK_SIZE ||
-           data.enc_key_len > sizeof(cont_encr_key) + AES_BLOCK_SIZE) {
-               wpa_printf(MSG_DEBUG, "DPP: Invalid encryptedKey length");
-               return -1;
-       }
-       res = aes_siv_decrypt(kek, data.pbkdf2_key_len,
-                             data.enc_key, data.enc_key_len,
-                             0, NULL, NULL, cont_encr_key);
-       forced_memzero(kek, data.pbkdf2_key_len);
-       if (res < 0) {
-               wpa_printf(MSG_DEBUG,
-                          "DPP: AES-SIV decryption of encryptedKey failed");
-               return -1;
-       }
-       cont_encr_key_len = data.enc_key_len - AES_BLOCK_SIZE;
-       wpa_hexdump_key(MSG_DEBUG, "DPP: content-encryption key",
-                       cont_encr_key, cont_encr_key_len);
-
-       if (data.enc_cont_len < AES_BLOCK_SIZE)
-               return -1;
-       key_pkg_len = data.enc_cont_len - AES_BLOCK_SIZE;
-       key_pkg = os_malloc(key_pkg_len);
-       if (!key_pkg)
-               return -1;
-       res = aes_siv_decrypt(cont_encr_key, cont_encr_key_len,
-                             data.enc_cont, data.enc_cont_len,
-                             0, NULL, NULL, key_pkg);
-       forced_memzero(cont_encr_key, cont_encr_key_len);
-       if (res < 0) {
-               bin_clear_free(key_pkg, key_pkg_len);
-               wpa_printf(MSG_DEBUG,
-                          "DPP: AES-SIV decryption of encryptedContent failed");
-               return -1;
-       }
-
-       keys = dpp_parse_dpp_asymmetric_key_package(key_pkg, key_pkg_len);
-       bin_clear_free(key_pkg, key_pkg_len);
-       dpp_free_asymmetric_key(auth->conf_key_pkg);
-       auth->conf_key_pkg = keys;
-
-       return keys != NULL;;
-}
-
-#endif /* CONFIG_DPP2 */
-
-
 int dpp_conf_resp_rx(struct dpp_authentication *auth,
                     const struct wpabuf *resp)
 {
diff --git a/src/common/dpp_backup.c b/src/common/dpp_backup.c
new file mode 100644 (file)
index 0000000..4bd5ba6
--- /dev/null
@@ -0,0 +1,1211 @@
+/*
+ * DPP configurator backup
+ * Copyright (c) 2019-2020, The Linux Foundation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <openssl/err.h>
+
+#include "utils/common.h"
+#include "crypto/aes.h"
+#include "crypto/aes_siv.h"
+#include "tls/asn1.h"
+#include "dpp.h"
+#include "dpp_i.h"
+
+#ifdef CONFIG_DPP2
+
+void dpp_free_asymmetric_key(struct dpp_asymmetric_key *key)
+{
+       while (key) {
+               struct dpp_asymmetric_key *next = key->next;
+
+               EVP_PKEY_free(key->csign);
+               str_clear_free(key->config_template);
+               str_clear_free(key->connector_template);
+               os_free(key);
+               key = next;
+       }
+}
+
+
+static struct wpabuf * dpp_build_conf_params(void)
+{
+       struct wpabuf *buf;
+       size_t len;
+       /* TODO: proper template values */
+       const char *conf_template = "{\"wi-fi_tech\":\"infra\",\"discovery\":{\"ssid\":\"test\"},\"cred\":{\"akm\":\"dpp\"}}";
+       const char *connector_template = NULL;
+
+       len = 100 + os_strlen(conf_template);
+       if (connector_template)
+               len += os_strlen(connector_template);
+       buf = wpabuf_alloc(len);
+       if (!buf)
+               return NULL;
+
+       /*
+        * DPPConfigurationParameters ::= SEQUENCE {
+        *    configurationTemplate     UTF8String,
+        *    connectorTemplate         UTF8String OPTIONAL}
+        */
+
+       asn1_put_utf8string(buf, conf_template);
+       if (connector_template)
+               asn1_put_utf8string(buf, connector_template);
+       return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+static struct wpabuf * dpp_build_attribute(void)
+{
+       struct wpabuf *conf_params, *attr;
+
+       /*
+        * aa-DPPConfigurationParameters ATTRIBUTE ::=
+        * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
+        *
+        * Attribute ::= SEQUENCE {
+        *    type OBJECT IDENTIFIER,
+        *    values SET SIZE(1..MAX) OF Type
+        */
+       conf_params = dpp_build_conf_params();
+       conf_params = asn1_encaps(conf_params, ASN1_CLASS_UNIVERSAL,
+                                 ASN1_TAG_SET);
+       if (!conf_params)
+               return NULL;
+
+       attr = wpabuf_alloc(100 + wpabuf_len(conf_params));
+       if (!attr) {
+               wpabuf_clear_free(conf_params);
+               return NULL;
+       }
+
+       asn1_put_oid(attr, &asn1_dpp_config_params_oid);
+       wpabuf_put_buf(attr, conf_params);
+       wpabuf_clear_free(conf_params);
+
+       return asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+static struct wpabuf * dpp_build_key_alg(const struct dpp_curve_params *curve)
+{
+       const struct asn1_oid *oid;
+       struct wpabuf *params, *res;
+
+       switch (curve->ike_group) {
+       case 19:
+               oid = &asn1_prime256v1_oid;
+               break;
+       case 20:
+               oid = &asn1_secp384r1_oid;
+               break;
+       case 21:
+               oid = &asn1_secp521r1_oid;
+               break;
+       case 28:
+               oid = &asn1_brainpoolP256r1_oid;
+               break;
+       case 29:
+               oid = &asn1_brainpoolP384r1_oid;
+               break;
+       case 30:
+               oid = &asn1_brainpoolP512r1_oid;
+               break;
+       default:
+               return NULL;
+       }
+
+       params = wpabuf_alloc(20);
+       if (!params)
+               return NULL;
+       asn1_put_oid(params, oid); /* namedCurve */
+
+       res = asn1_build_alg_id(&asn1_ec_public_key_oid, params);
+       wpabuf_free(params);
+       return res;
+}
+
+
+static struct wpabuf * dpp_build_key_pkg(struct dpp_authentication *auth)
+{
+       struct wpabuf *key = NULL, *attr, *alg, *priv_key = NULL;
+       EC_KEY *eckey;
+       unsigned char *der = NULL;
+       int der_len;
+
+       eckey = EVP_PKEY_get0_EC_KEY(auth->conf->csign);
+       if (!eckey)
+               return NULL;
+
+       EC_KEY_set_enc_flags(eckey, EC_PKEY_NO_PUBKEY);
+       der_len = i2d_ECPrivateKey(eckey, &der);
+       if (der_len > 0)
+               priv_key = wpabuf_alloc_copy(der, der_len);
+       OPENSSL_free(der);
+
+       alg = dpp_build_key_alg(auth->conf->curve);
+
+       /* Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } */
+       attr = dpp_build_attribute();
+       attr = asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SET);
+       if (!priv_key || !attr || !alg)
+               goto fail;
+
+       /*
+        * OneAsymmetricKey ::= SEQUENCE {
+        *    version                   Version,
+        *    privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
+        *    privateKey                PrivateKey,
+        *    attributes                [0] Attributes OPTIONAL,
+        *    ...,
+        *    [[2: publicKey            [1] BIT STRING OPTIONAL ]],
+        *    ...
+        * }
+        */
+
+       key = wpabuf_alloc(100 + wpabuf_len(alg) + wpabuf_len(priv_key) +
+                          wpabuf_len(attr));
+       if (!key)
+               goto fail;
+
+       asn1_put_integer(key, 1); /* version = v2(1) */
+
+       /* PrivateKeyAlgorithmIdentifier */
+       wpabuf_put_buf(key, alg);
+
+       /* PrivateKey ::= OCTET STRING */
+       asn1_put_octet_string(key, priv_key);
+
+       /* [0] Attributes OPTIONAL */
+       asn1_put_hdr(key, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0, wpabuf_len(attr));
+       wpabuf_put_buf(key, attr);
+
+fail:
+       wpabuf_clear_free(attr);
+       wpabuf_clear_free(priv_key);
+       wpabuf_free(alg);
+
+       /*
+        * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
+        *
+        * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
+        *
+        * OneAsymmetricKey ::= SEQUENCE
+        */
+       return asn1_encaps(asn1_encaps(key,
+                                      ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE),
+                          ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+static struct wpabuf * dpp_build_pbkdf2_alg_id(const struct wpabuf *salt,
+                                              size_t hash_len)
+{
+       struct wpabuf *params = NULL, *buf = NULL, *prf = NULL;
+       const struct asn1_oid *oid;
+
+       /*
+        * PBKDF2-params ::= SEQUENCE {
+        *    salt CHOICE {
+        *       specified OCTET STRING,
+        *       otherSource AlgorithmIdentifier}
+        *    iterationCount INTEGER (1..MAX),
+        *    keyLength INTEGER (1..MAX),
+        *    prf AlgorithmIdentifier}
+        *
+        * salt is an 64 octet value, iterationCount is 1000, keyLength is based
+        * on Configurator signing key length, prf is
+        * id-hmacWithSHA{256,384,512} based on Configurator signing key.
+        */
+
+       if (hash_len == 32)
+               oid = &asn1_pbkdf2_hmac_sha256_oid;
+       else if (hash_len == 48)
+               oid = &asn1_pbkdf2_hmac_sha384_oid;
+       else if (hash_len == 64)
+               oid = &asn1_pbkdf2_hmac_sha512_oid;
+       else
+               goto fail;
+       prf = asn1_build_alg_id(oid, NULL);
+       if (!prf)
+               goto fail;
+       params = wpabuf_alloc(100 + wpabuf_len(salt) + wpabuf_len(prf));
+       if (!params)
+               goto fail;
+       asn1_put_octet_string(params, salt); /* salt.specified */
+       asn1_put_integer(params, 1000); /* iterationCount */
+       asn1_put_integer(params, hash_len); /* keyLength */
+       wpabuf_put_buf(params, prf);
+       params = asn1_encaps(params, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+       if (!params)
+               goto fail;
+       buf = asn1_build_alg_id(&asn1_pbkdf2_oid, params);
+fail:
+       wpabuf_free(params);
+       wpabuf_free(prf);
+       return buf;
+}
+
+
+static struct wpabuf *
+dpp_build_pw_recipient_info(struct dpp_authentication *auth, size_t hash_len,
+                           const struct wpabuf *cont_enc_key)
+{
+       struct wpabuf *pwri = NULL, *enc_key = NULL, *key_der_alg = NULL,
+               *key_enc_alg = NULL, *salt;
+       u8 kek[DPP_MAX_HASH_LEN];
+       const u8 *key;
+       size_t key_len;
+
+       salt = wpabuf_alloc(64);
+       if (!salt || os_get_random(wpabuf_put(salt, 64), 64) < 0)
+               goto fail;
+       wpa_hexdump_buf(MSG_DEBUG, "DPP: PBKDF2 salt", salt);
+
+       /* TODO: For initial testing, use ke as the key. Replace this with a
+        * new key once that has been defined. */
+       key = auth->ke;
+       key_len = auth->curve->hash_len;
+       wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
+
+       if (dpp_pbkdf2(hash_len, key, key_len, wpabuf_head(salt), 64, 1000,
+                      kek, hash_len)) {
+               wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed");
+               goto fail;
+       }
+       wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2",
+                       kek, hash_len);
+
+       enc_key = wpabuf_alloc(hash_len + AES_BLOCK_SIZE);
+       if (!enc_key ||
+           aes_siv_encrypt(kek, hash_len, wpabuf_head(cont_enc_key),
+                           wpabuf_len(cont_enc_key), 0, NULL, NULL,
+                           wpabuf_put(enc_key, hash_len + AES_BLOCK_SIZE)) < 0)
+               goto fail;
+       wpa_hexdump_buf(MSG_DEBUG, "DPP: encryptedKey", enc_key);
+
+       /*
+        * PasswordRecipientInfo ::= SEQUENCE {
+        *    version                   CMSVersion,
+        *    keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
+        *    keyEncryptionAlgorithm    KeyEncryptionAlgorithmIdentifier,
+        *    encryptedKey              EncryptedKey}
+        *
+        * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
+        * parameters contains PBKDF2-params SEQUENCE.
+        */
+
+       key_der_alg = dpp_build_pbkdf2_alg_id(salt, hash_len);
+       key_enc_alg = asn1_build_alg_id(&asn1_aes_siv_cmac_aead_256_oid, NULL);
+       if (!key_der_alg || !key_enc_alg)
+               goto fail;
+       pwri = wpabuf_alloc(100 + wpabuf_len(key_der_alg) +
+                           wpabuf_len(key_enc_alg) + wpabuf_len(enc_key));
+       if (!pwri)
+               goto fail;
+
+       /* version = 0 */
+       asn1_put_integer(pwri, 0);
+
+       /* [0] KeyDerivationAlgorithmIdentifier */
+       asn1_put_hdr(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0,
+                    wpabuf_len(key_der_alg));
+       wpabuf_put_buf(pwri, key_der_alg);
+
+       /* KeyEncryptionAlgorithmIdentifier */
+       wpabuf_put_buf(pwri, key_enc_alg);
+
+       /* EncryptedKey ::= OCTET STRING */
+       asn1_put_octet_string(pwri, enc_key);
+
+fail:
+       wpabuf_clear_free(key_der_alg);
+       wpabuf_free(key_enc_alg);
+       wpabuf_free(enc_key);
+       wpabuf_free(salt);
+       forced_memzero(kek, sizeof(kek));
+       return asn1_encaps(pwri, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+}
+
+
+static struct wpabuf *
+dpp_build_recipient_info(struct dpp_authentication *auth, size_t hash_len,
+                        const struct wpabuf *cont_enc_key)
+{
+       struct wpabuf *pwri;
+
+       /*
+        * RecipientInfo ::= CHOICE {
+        *    ktri              KeyTransRecipientInfo,
+        *    kari      [1]     KeyAgreeRecipientInfo,
+        *    kekri     [2]     KEKRecipientInfo,
+        *    pwri      [3]     PasswordRecipientInfo,
+        *    ori       [4]     OtherRecipientInfo}
+        *
+        * Shall always use the pwri CHOICE.
+        */
+
+       pwri = dpp_build_pw_recipient_info(auth, hash_len, cont_enc_key);
+       return asn1_encaps(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 3);
+}
+
+
+static struct wpabuf *
+dpp_build_enc_cont_info(struct dpp_authentication *auth, size_t hash_len,
+                       const struct wpabuf *cont_enc_key)
+{
+       struct wpabuf *key_pkg, *enc_cont_info = NULL, *enc_cont = NULL,
+               *enc_alg;
+       const struct asn1_oid *oid;
+       size_t enc_cont_len;
+
+       /*
+        * EncryptedContentInfo ::= SEQUENCE {
+        *    contentType                       ContentType,
+        *    contentEncryptionAlgorithm  ContentEncryptionAlgorithmIdentifier,
+        *    encryptedContent  [0] IMPLICIT    EncryptedContent OPTIONAL}
+        */
+
+       if (hash_len == 32)
+               oid = &asn1_aes_siv_cmac_aead_256_oid;
+       else if (hash_len == 48)
+               oid = &asn1_aes_siv_cmac_aead_384_oid;
+       else if (hash_len == 64)
+               oid = &asn1_aes_siv_cmac_aead_512_oid;
+       else
+               return NULL;
+
+       key_pkg = dpp_build_key_pkg(auth);
+       enc_alg = asn1_build_alg_id(oid, NULL);
+       if (!key_pkg || !enc_alg)
+               goto fail;
+
+       wpa_hexdump_buf_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage",
+                           key_pkg);
+
+       enc_cont_len = wpabuf_len(key_pkg) + AES_BLOCK_SIZE;
+       enc_cont = wpabuf_alloc(enc_cont_len);
+       if (!enc_cont ||
+           aes_siv_encrypt(wpabuf_head(cont_enc_key), wpabuf_len(cont_enc_key),
+                           wpabuf_head(key_pkg), wpabuf_len(key_pkg),
+                           0, NULL, NULL,
+                           wpabuf_put(enc_cont, enc_cont_len)) < 0)
+               goto fail;
+
+       enc_cont_info = wpabuf_alloc(100 + wpabuf_len(enc_alg) +
+                                    wpabuf_len(enc_cont));
+       if (!enc_cont_info)
+               goto fail;
+
+       /* ContentType ::= OBJECT IDENTIFIER */
+       asn1_put_oid(enc_cont_info, &asn1_dpp_asymmetric_key_package_oid);
+
+       /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
+       wpabuf_put_buf(enc_cont_info, enc_alg);
+
+       /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+        * EncryptedContent ::= OCTET STRING */
+       asn1_put_hdr(enc_cont_info, ASN1_CLASS_CONTEXT_SPECIFIC, 0, 0,
+                    wpabuf_len(enc_cont));
+       wpabuf_put_buf(enc_cont_info, enc_cont);
+
+fail:
+       wpabuf_clear_free(key_pkg);
+       wpabuf_free(enc_cont);
+       wpabuf_free(enc_alg);
+       return enc_cont_info;
+}
+
+
+static struct wpabuf * dpp_gen_random(size_t len)
+{
+       struct wpabuf *key;
+
+       key = wpabuf_alloc(len);
+       if (!key || os_get_random(wpabuf_put(key, len), len) < 0) {
+               wpabuf_free(key);
+               key = NULL;
+       }
+       wpa_hexdump_buf_key(MSG_DEBUG, "DPP: content-encryption key", key);
+       return key;
+}
+
+
+struct wpabuf * dpp_build_enveloped_data(struct dpp_authentication *auth)
+{
+       struct wpabuf *env = NULL;
+       struct wpabuf *recipient_info = NULL, *enc_cont_info = NULL;
+       struct wpabuf *cont_enc_key = NULL;
+       size_t hash_len;
+
+       if (!auth->conf) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: No Configurator instance selected for the session - cannot build DPPEnvelopedData");
+               return NULL;
+       }
+
+       if (!auth->provision_configurator) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Configurator provisioning not allowed");
+               return NULL;
+       }
+
+       wpa_printf(MSG_DEBUG, "DPP: Building DPPEnvelopedData");
+
+       hash_len = auth->conf->curve->hash_len;
+       cont_enc_key = dpp_gen_random(hash_len);
+       if (!cont_enc_key)
+               goto fail;
+       recipient_info = dpp_build_recipient_info(auth, hash_len, cont_enc_key);
+       enc_cont_info = dpp_build_enc_cont_info(auth, hash_len, cont_enc_key);
+       if (!recipient_info || !enc_cont_info)
+               goto fail;
+
+       env = wpabuf_alloc(wpabuf_len(recipient_info) +
+                          wpabuf_len(enc_cont_info) +
+                          100);
+       if (!env)
+               goto fail;
+
+       /*
+        * DPPEnvelopedData ::= EnvelopedData
+        *
+        * EnvelopedData ::= SEQUENCE {
+        *    version                   CMSVersion,
+        *    originatorInfo    [0]     IMPLICIT OriginatorInfo OPTIONAL,
+        *    recipientInfos            RecipientInfos,
+        *    encryptedContentInfo      EncryptedContentInfo,
+        *    unprotectedAttrs  [1] IMPLICIT    UnprotectedAttributes OPTIONAL}
+        *
+        * For DPP, version is 3, both originatorInfo and
+        * unprotectedAttrs are omitted, and recipientInfos contains a single
+        * RecipientInfo.
+        */
+
+       /* EnvelopedData.version = 3 */
+       asn1_put_integer(env, 3);
+
+       /* RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo */
+       asn1_put_set(env, recipient_info);
+
+       /* EncryptedContentInfo ::= SEQUENCE */
+       asn1_put_sequence(env, enc_cont_info);
+
+       env = asn1_encaps(env, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE);
+       wpa_hexdump_buf(MSG_MSGDUMP, "DPP: DPPEnvelopedData", env);
+out:
+       wpabuf_clear_free(cont_enc_key);
+       wpabuf_clear_free(recipient_info);
+       wpabuf_free(enc_cont_info);
+       return env;
+fail:
+       wpabuf_free(env);
+       env = NULL;
+       goto out;
+}
+
+
+struct dpp_enveloped_data {
+       const u8 *enc_cont;
+       size_t enc_cont_len;
+       const u8 *enc_key;
+       size_t enc_key_len;
+       const u8 *salt;
+       size_t pbkdf2_key_len;
+       size_t prf_hash_len;
+};
+
+
+static int dpp_parse_recipient_infos(const u8 *pos, size_t len,
+                                    struct dpp_enveloped_data *data)
+{
+       struct asn1_hdr hdr;
+       const u8 *end = pos + len;
+       const u8 *next, *e_end;
+       struct asn1_oid oid;
+       int val;
+       const u8 *params;
+       size_t params_len;
+
+       wpa_hexdump(MSG_MSGDUMP, "DPP: RecipientInfos", pos, len);
+
+       /*
+        * RecipientInfo ::= CHOICE {
+        *    ktri              KeyTransRecipientInfo,
+        *    kari      [1]     KeyAgreeRecipientInfo,
+        *    kekri     [2]     KEKRecipientInfo,
+        *    pwri      [3]     PasswordRecipientInfo,
+        *    ori       [4]     OtherRecipientInfo}
+        *
+        * Shall always use the pwri CHOICE.
+        */
+
+       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+           hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 3) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Expected CHOICE [3] (pwri) - found class %d tag 0x%x",
+                          hdr.class, hdr.tag);
+               return -1;
+       }
+       wpa_hexdump(MSG_MSGDUMP, "DPP: PasswordRecipientInfo",
+                   hdr.payload, hdr.length);
+       pos = hdr.payload;
+       end = pos + hdr.length;
+
+       /*
+        * PasswordRecipientInfo ::= SEQUENCE {
+        *    version                   CMSVersion,
+        *    keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL,
+        *    keyEncryptionAlgorithm    KeyEncryptionAlgorithmIdentifier,
+        *    encryptedKey              EncryptedKey}
+        *
+        * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the
+        * parameters contains PBKDF2-params SEQUENCE.
+        */
+
+       if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0)
+               return -1;
+       pos = hdr.payload;
+
+       if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
+               return -1;
+       if (val != 0) {
+               wpa_printf(MSG_DEBUG, "DPP: pwri.version != 0");
+               return -1;
+       }
+
+       wpa_hexdump(MSG_MSGDUMP, "DPP: Remaining PasswordRecipientInfo after version",
+                   pos, end - pos);
+
+       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+           hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Expected keyDerivationAlgorithm [0] - found class %d tag 0x%x",
+                          hdr.class, hdr.tag);
+               return -1;
+       }
+       pos = hdr.payload;
+       e_end = pos + hdr.length;
+
+       /* KeyDerivationAlgorithmIdentifier ::= AlgorithmIdentifier */
+       if (asn1_get_alg_id(pos, e_end - pos, &oid, &params, &params_len,
+                           &next) < 0)
+               return -1;
+       if (!asn1_oid_equal(&oid, &asn1_pbkdf2_oid)) {
+               char buf[80];
+
+               asn1_oid_to_str(&oid, buf, sizeof(buf));
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Unexpected KeyDerivationAlgorithmIdentifier %s",
+                          buf);
+               return -1;
+       }
+
+       /*
+        * PBKDF2-params ::= SEQUENCE {
+        *    salt CHOICE {
+        *       specified OCTET STRING,
+        *       otherSource AlgorithmIdentifier}
+        *    iterationCount INTEGER (1..MAX),
+        *    keyLength INTEGER (1..MAX),
+        *    prf AlgorithmIdentifier}
+        *
+        * salt is an 64 octet value, iterationCount is 1000, keyLength is based
+        * on Configurator signing key length, prf is
+        * id-hmacWithSHA{256,384,512} based on Configurator signing key.
+        */
+       if (!params ||
+           asn1_get_sequence(params, params_len, &hdr, &e_end) < 0)
+               return -1;
+       pos = hdr.payload;
+
+       if (asn1_get_next(pos, e_end - pos, &hdr) < 0 ||
+           hdr.class != ASN1_CLASS_UNIVERSAL ||
+           hdr.tag != ASN1_TAG_OCTETSTRING) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Expected OCTETSTRING (salt.specified) - found class %d tag 0x%x",
+                          hdr.class, hdr.tag);
+               return -1;
+       }
+       wpa_hexdump(MSG_MSGDUMP, "DPP: salt.specified",
+                   hdr.payload, hdr.length);
+       if (hdr.length != 64) {
+               wpa_printf(MSG_DEBUG, "DPP: Unexpected salt length %u",
+                          hdr.length);
+               return -1;
+       }
+       data->salt = hdr.payload;
+       pos = hdr.payload + hdr.length;
+
+       if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0)
+               return -1;
+       if (val != 1000) {
+               wpa_printf(MSG_DEBUG, "DPP: Unexpected iterationCount %d", val);
+               return -1;
+       }
+
+       if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0)
+               return -1;
+       if (val != 32 && val != 48 && val != 64) {
+               wpa_printf(MSG_DEBUG, "DPP: Unexpected keyLength %d", val);
+               return -1;
+       }
+       data->pbkdf2_key_len = val;
+
+       if (asn1_get_sequence(pos, e_end - pos, &hdr, NULL) < 0 ||
+           asn1_get_oid(hdr.payload, hdr.length, &oid, &pos) < 0) {
+               wpa_printf(MSG_DEBUG, "DPP: Could not parse prf");
+               return -1;
+       }
+       if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha256_oid)) {
+               data->prf_hash_len = 32;
+       } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha384_oid)) {
+               data->prf_hash_len = 48;
+       } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha512_oid)) {
+               data->prf_hash_len = 64;
+       } else {
+               char buf[80];
+
+               asn1_oid_to_str(&oid, buf, sizeof(buf));
+               wpa_printf(MSG_DEBUG, "DPP: Unexpected PBKDF2-params.prf %s",
+                          buf);
+               return -1;
+       }
+
+       pos = next;
+
+       /* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier
+        *
+        * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+        *
+        * id-alg-AES-SIV-CMAC-aed-256, id-alg-AES-SIV-CMAC-aed-384, or
+        * id-alg-AES-SIV-CMAC-aed-512. */
+       if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0)
+               return -1;
+       if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) &&
+           !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) &&
+           !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) {
+               char buf[80];
+
+               asn1_oid_to_str(&oid, buf, sizeof(buf));
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Unexpected KeyEncryptionAlgorithmIdentifier %s",
+                          buf);
+               return -1;
+       }
+
+       /*
+        * encryptedKey EncryptedKey
+        *
+        * EncryptedKey ::= OCTET STRING
+        */
+       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+           hdr.class != ASN1_CLASS_UNIVERSAL ||
+           hdr.tag != ASN1_TAG_OCTETSTRING) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Expected OCTETSTRING (pwri.encryptedKey) - found class %d tag 0x%x",
+                          hdr.class, hdr.tag);
+               return -1;
+       }
+       wpa_hexdump(MSG_MSGDUMP, "DPP: pwri.encryptedKey",
+                   hdr.payload, hdr.length);
+       data->enc_key = hdr.payload;
+       data->enc_key_len = hdr.length;
+
+       return 0;
+}
+
+
+static int dpp_parse_encrypted_content_info(const u8 *pos, const u8 *end,
+                                           struct dpp_enveloped_data *data)
+{
+       struct asn1_hdr hdr;
+       struct asn1_oid oid;
+
+       /*
+        * EncryptedContentInfo ::= SEQUENCE {
+        *    contentType                       ContentType,
+        *    contentEncryptionAlgorithm  ContentEncryptionAlgorithmIdentifier,
+        *    encryptedContent  [0] IMPLICIT    EncryptedContent OPTIONAL}
+        */
+       if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
+               return -1;
+       wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContentInfo",
+                   hdr.payload, hdr.length);
+       if (pos < end) {
+               wpa_hexdump(MSG_DEBUG,
+                           "DPP: Unexpected extra data after EncryptedContentInfo",
+                           pos, end - pos);
+               return -1;
+       }
+
+       end = pos;
+       pos = hdr.payload;
+
+       /* ContentType ::= OBJECT IDENTIFIER */
+       if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) {
+               wpa_printf(MSG_DEBUG, "DPP: Could not parse ContentType");
+               return -1;
+       }
+       if (!asn1_oid_equal(&oid, &asn1_dpp_asymmetric_key_package_oid)) {
+               char buf[80];
+
+               asn1_oid_to_str(&oid, buf, sizeof(buf));
+               wpa_printf(MSG_DEBUG, "DPP: Unexpected ContentType %s", buf);
+               return -1;
+       }
+
+       /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */
+       if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0)
+               return -1;
+       if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) &&
+           !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) &&
+           !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) {
+               char buf[80];
+
+               asn1_oid_to_str(&oid, buf, sizeof(buf));
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Unexpected ContentEncryptionAlgorithmIdentifier %s",
+                          buf);
+               return -1;
+       }
+       /* ignore optional parameters */
+
+       /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL
+        * EncryptedContent ::= OCTET STRING */
+       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+           hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Expected [0] IMPLICIT (EncryptedContent) - found class %d tag 0x%x",
+                          hdr.class, hdr.tag);
+               return -1;
+       }
+       wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContent",
+                   hdr.payload, hdr.length);
+       data->enc_cont = hdr.payload;
+       data->enc_cont_len = hdr.length;
+       return 0;
+}
+
+
+static int dpp_parse_enveloped_data(const u8 *env_data, size_t env_data_len,
+                                   struct dpp_enveloped_data *data)
+{
+       struct asn1_hdr hdr;
+       const u8 *pos, *end;
+       int val;
+
+       os_memset(data, 0, sizeof(*data));
+
+       /*
+        * DPPEnvelopedData ::= EnvelopedData
+        *
+        * EnvelopedData ::= SEQUENCE {
+        *    version                   CMSVersion,
+        *    originatorInfo    [0]     IMPLICIT OriginatorInfo OPTIONAL,
+        *    recipientInfos            RecipientInfos,
+        *    encryptedContentInfo      EncryptedContentInfo,
+        *    unprotectedAttrs  [1] IMPLICIT    UnprotectedAttributes OPTIONAL}
+        *
+        * CMSVersion ::= INTEGER
+        *
+        * RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo
+        *
+        * For DPP, version is 3, both originatorInfo and
+        * unprotectedAttrs are omitted, and recipientInfos contains a single
+        * RecipientInfo.
+        */
+       if (asn1_get_sequence(env_data, env_data_len, &hdr, &end) < 0)
+               return -1;
+       pos = hdr.payload;
+       if (end < env_data + env_data_len) {
+               wpa_hexdump(MSG_DEBUG,
+                           "DPP: Unexpected extra data after DPPEnvelopedData",
+                           end, env_data + env_data_len - end);
+               return -1;
+       }
+
+       if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
+               return -1;
+       if (val != 3) {
+               wpa_printf(MSG_DEBUG, "DPP: EnvelopedData.version != 3");
+               return -1;
+       }
+
+       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+           hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Expected SET (RecipientInfos) - found class %d tag 0x%x",
+                          hdr.class, hdr.tag);
+               return -1;
+       }
+
+       if (dpp_parse_recipient_infos(hdr.payload, hdr.length, data) < 0)
+               return -1;
+       return dpp_parse_encrypted_content_info(hdr.payload + hdr.length, end,
+                                               data);
+}
+
+
+static struct dpp_asymmetric_key *
+dpp_parse_one_asymmetric_key(const u8 *buf, size_t len)
+{
+       struct asn1_hdr hdr;
+       const u8 *pos = buf, *end = buf + len, *next;
+       int val;
+       const u8 *params;
+       size_t params_len;
+       struct asn1_oid oid;
+       char txt[80];
+       struct dpp_asymmetric_key *key;
+       EC_KEY *eckey;
+
+       wpa_hexdump_key(MSG_MSGDUMP, "DPP: OneAsymmetricKey", buf, len);
+
+       key = os_zalloc(sizeof(*key));
+       if (!key)
+               return NULL;
+
+       /*
+        * OneAsymmetricKey ::= SEQUENCE {
+        *    version                   Version,
+        *    privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
+        *    privateKey                PrivateKey,
+        *    attributes                [0] Attributes OPTIONAL,
+        *    ...,
+        *    [[2: publicKey            [1] BIT STRING OPTIONAL ]],
+        *    ...
+        * }
+        */
+       if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0)
+               goto fail;
+       pos = hdr.payload;
+
+       /* Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) */
+       if (asn1_get_integer(pos, end - pos, &val, &pos) < 0)
+               goto fail;
+       if (val != 1) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Unsupported DPPAsymmetricKeyPackage version %d",
+                          val);
+               goto fail;
+       }
+
+       /* PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier */
+       if (asn1_get_alg_id(pos, end - pos, &oid, &params, &params_len,
+                           &pos) < 0)
+               goto fail;
+       if (!asn1_oid_equal(&oid, &asn1_ec_public_key_oid)) {
+               asn1_oid_to_str(&oid, txt, sizeof(txt));
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Unsupported PrivateKeyAlgorithmIdentifier %s",
+                          txt);
+               goto fail;
+       }
+       wpa_hexdump(MSG_MSGDUMP, "DPP: PrivateKeyAlgorithmIdentifier params",
+                   params, params_len);
+       /*
+        * ECParameters ::= CHOICE {
+        *    namedCurve        OBJECT IDENTIFIER
+        *    -- implicitCurve  NULL
+        *    -- specifiedCurve SpecifiedECDomain}
+        */
+       if (!params || asn1_get_oid(params, params_len, &oid, &next) < 0) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Could not parse ECParameters.namedCurve");
+               goto fail;
+       }
+       asn1_oid_to_str(&oid, txt, sizeof(txt));
+       wpa_printf(MSG_MSGDUMP, "DPP: namedCurve %s", txt);
+       /* Assume the curve is identified within ECPrivateKey, so that this
+        * separate indication is not really needed. */
+
+       /*
+        * PrivateKey ::= OCTET STRING
+        *    (Contains DER encoding of ECPrivateKey)
+        */
+       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+           hdr.class != ASN1_CLASS_UNIVERSAL ||
+           hdr.tag != ASN1_TAG_OCTETSTRING) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Expected OCTETSTRING (PrivateKey) - found class %d tag 0x%x",
+                          hdr.class, hdr.tag);
+               goto fail;
+       }
+       wpa_hexdump_key(MSG_MSGDUMP, "DPP: PrivateKey",
+                       hdr.payload, hdr.length);
+       pos = hdr.payload + hdr.length;
+       eckey = d2i_ECPrivateKey(NULL, &hdr.payload, hdr.length);
+       if (!eckey) {
+               wpa_printf(MSG_INFO,
+                          "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s",
+                          ERR_error_string(ERR_get_error(), NULL));
+               goto fail;
+       }
+       key->csign = EVP_PKEY_new();
+       if (!key->csign || EVP_PKEY_assign_EC_KEY(key->csign, eckey) != 1) {
+               EC_KEY_free(eckey);
+               goto fail;
+       }
+       if (wpa_debug_show_keys)
+               dpp_debug_print_key("DPP: Received c-sign-key", key->csign);
+
+       /*
+        * Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } }
+        *
+        * Exactly one instance of type Attribute in OneAsymmetricKey.
+        */
+       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+           hdr.class != ASN1_CLASS_CONTEXT_SPECIFIC || hdr.tag != 0) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Expected [0] Attributes - found class %d tag 0x%x",
+                          hdr.class, hdr.tag);
+               goto fail;
+       }
+       wpa_hexdump_key(MSG_MSGDUMP, "DPP: Attributes",
+                       hdr.payload, hdr.length);
+       if (hdr.payload + hdr.length < end) {
+               wpa_hexdump_key(MSG_MSGDUMP,
+                               "DPP: Ignore additional data at the end of OneAsymmetricKey",
+                               hdr.payload + hdr.length,
+                               end - (hdr.payload + hdr.length));
+       }
+       pos = hdr.payload;
+       end = hdr.payload + hdr.length;
+
+       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+           hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Expected SET (Attributes) - found class %d tag 0x%x",
+                          hdr.class, hdr.tag);
+               goto fail;
+       }
+       if (hdr.payload + hdr.length < end) {
+               wpa_hexdump_key(MSG_MSGDUMP,
+                               "DPP: Ignore additional data at the end of OneAsymmetricKey (after SET)",
+                               hdr.payload + hdr.length,
+                               end - (hdr.payload + hdr.length));
+       }
+       pos = hdr.payload;
+       end = hdr.payload + hdr.length;
+
+       /*
+        * OneAsymmetricKeyAttributes ATTRIBUTE ::= {
+        *    aa-DPPConfigurationParameters,
+        *    ... -- For local profiles
+        * }
+        *
+        * aa-DPPConfigurationParameters ATTRIBUTE ::=
+        * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams }
+        *
+        * Attribute ::= SEQUENCE {
+        *    type OBJECT IDENTIFIER,
+        *    values SET SIZE(1..MAX) OF Type
+        *
+        * Exactly one instance of ATTRIBUTE in attrValues.
+        */
+       if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
+               goto fail;
+       if (pos < end) {
+               wpa_hexdump_key(MSG_MSGDUMP,
+                               "DPP: Ignore additional data at the end of ATTRIBUTE",
+                               pos, end - pos);
+       }
+       end = pos;
+       pos = hdr.payload;
+
+       if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0)
+               goto fail;
+       if (!asn1_oid_equal(&oid, &asn1_dpp_config_params_oid)) {
+               asn1_oid_to_str(&oid, txt, sizeof(txt));
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Unexpected Attribute identifier %s", txt);
+               goto fail;
+       }
+
+       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+           hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_SET) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Expected SET (Attribute) - found class %d tag 0x%x",
+                          hdr.class, hdr.tag);
+               goto fail;
+       }
+       pos = hdr.payload;
+       end = hdr.payload + hdr.length;
+
+       /*
+        * DPPConfigurationParameters ::= SEQUENCE {
+        *    configurationTemplate     UTF8String,
+        *    connectorTemplate         UTF8String OPTIONAL}
+        */
+
+       wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPConfigurationParameters",
+                       pos, end - pos);
+       if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0)
+               goto fail;
+       if (pos < end) {
+               wpa_hexdump_key(MSG_MSGDUMP,
+                               "DPP: Ignore additional data after DPPConfigurationParameters",
+                               pos, end - pos);
+       }
+       end = pos;
+       pos = hdr.payload;
+
+       if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+           hdr.class != ASN1_CLASS_UNIVERSAL ||
+           hdr.tag != ASN1_TAG_UTF8STRING) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: Expected UTF8STRING (configurationTemplate) - found class %d tag 0x%x",
+                          hdr.class, hdr.tag);
+               goto fail;
+       }
+       wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: configurationTemplate",
+                             hdr.payload, hdr.length);
+       key->config_template = os_zalloc(hdr.length + 1);
+       if (!key->config_template)
+               goto fail;
+       os_memcpy(key->config_template, hdr.payload, hdr.length);
+
+       pos = hdr.payload + hdr.length;
+
+       if (pos < end) {
+               if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
+                   hdr.class != ASN1_CLASS_UNIVERSAL ||
+                   hdr.tag != ASN1_TAG_UTF8STRING) {
+                       wpa_printf(MSG_DEBUG,
+                                  "DPP: Expected UTF8STRING (connectorTemplate) - found class %d tag 0x%x",
+                                  hdr.class, hdr.tag);
+                       goto fail;
+               }
+               wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: connectorTemplate",
+                                     hdr.payload, hdr.length);
+               key->connector_template = os_zalloc(hdr.length + 1);
+               if (!key->connector_template)
+                       goto fail;
+               os_memcpy(key->connector_template, hdr.payload, hdr.length);
+       }
+
+       return key;
+fail:
+       wpa_printf(MSG_DEBUG, "DPP: Failed to parse OneAsymmetricKey");
+       dpp_free_asymmetric_key(key);
+       return NULL;
+}
+
+
+static struct dpp_asymmetric_key *
+dpp_parse_dpp_asymmetric_key_package(const u8 *key_pkg, size_t key_pkg_len)
+{
+       struct asn1_hdr hdr;
+       const u8 *pos = key_pkg, *end = key_pkg + key_pkg_len;
+       struct dpp_asymmetric_key *first = NULL, *last = NULL, *key;
+
+       wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage",
+                       key_pkg, key_pkg_len);
+
+       /*
+        * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage
+        *
+        * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey
+        */
+       while (pos < end) {
+               if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0 ||
+                   !(key = dpp_parse_one_asymmetric_key(hdr.payload,
+                                                        hdr.length))) {
+                       dpp_free_asymmetric_key(first);
+                       return NULL;
+               }
+               if (!last) {
+                       first = last = key;
+               } else {
+                       last->next = key;
+                       last = key;
+               }
+       }
+
+       return first;
+}
+
+
+int dpp_conf_resp_env_data(struct dpp_authentication *auth,
+                          const u8 *env_data, size_t env_data_len)
+{
+       const u8 *key;
+       size_t key_len;
+       u8 kek[DPP_MAX_HASH_LEN];
+       u8 cont_encr_key[DPP_MAX_HASH_LEN];
+       size_t cont_encr_key_len;
+       int res;
+       u8 *key_pkg;
+       size_t key_pkg_len;
+       struct dpp_enveloped_data data;
+       struct dpp_asymmetric_key *keys;
+
+       wpa_hexdump(MSG_DEBUG, "DPP: DPPEnvelopedData", env_data, env_data_len);
+
+       if (dpp_parse_enveloped_data(env_data, env_data_len, &data) < 0)
+               return -1;
+
+       /* TODO: For initial testing, use ke as the key. Replace this with a
+        * new key once that has been defined. */
+       key = auth->ke;
+       key_len = auth->curve->hash_len;
+       wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len);
+
+       if (dpp_pbkdf2(data.prf_hash_len, key, key_len, data.salt, 64, 1000,
+                      kek, data.pbkdf2_key_len)) {
+               wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed");
+               return -1;
+       }
+       wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2",
+                       kek, data.pbkdf2_key_len);
+
+       if (data.enc_key_len < AES_BLOCK_SIZE ||
+           data.enc_key_len > sizeof(cont_encr_key) + AES_BLOCK_SIZE) {
+               wpa_printf(MSG_DEBUG, "DPP: Invalid encryptedKey length");
+               return -1;
+       }
+       res = aes_siv_decrypt(kek, data.pbkdf2_key_len,
+                             data.enc_key, data.enc_key_len,
+                             0, NULL, NULL, cont_encr_key);
+       forced_memzero(kek, data.pbkdf2_key_len);
+       if (res < 0) {
+               wpa_printf(MSG_DEBUG,
+                          "DPP: AES-SIV decryption of encryptedKey failed");
+               return -1;
+       }
+       cont_encr_key_len = data.enc_key_len - AES_BLOCK_SIZE;
+       wpa_hexdump_key(MSG_DEBUG, "DPP: content-encryption key",
+                       cont_encr_key, cont_encr_key_len);
+
+       if (data.enc_cont_len < AES_BLOCK_SIZE)
+               return -1;
+       key_pkg_len = data.enc_cont_len - AES_BLOCK_SIZE;
+       key_pkg = os_malloc(key_pkg_len);
+       if (!key_pkg)
+               return -1;
+       res = aes_siv_decrypt(cont_encr_key, cont_encr_key_len,
+                             data.enc_cont, data.enc_cont_len,
+                             0, NULL, NULL, key_pkg);
+       forced_memzero(cont_encr_key, cont_encr_key_len);
+       if (res < 0) {
+               bin_clear_free(key_pkg, key_pkg_len);
+               wpa_printf(MSG_DEBUG,
+                          "DPP: AES-SIV decryption of encryptedContent failed");
+               return -1;
+       }
+
+       keys = dpp_parse_dpp_asymmetric_key_package(key_pkg, key_pkg_len);
+       bin_clear_free(key_pkg, key_pkg_len);
+       dpp_free_asymmetric_key(auth->conf_key_pkg);
+       auth->conf_key_pkg = keys;
+
+       return keys != NULL;
+}
+
+#endif /* CONFIG_DPP2 */
index 490e5bc93e0e8e4f7562ebd9de20b5764b8eb02e..c81411a9b0850e4f684435ff832c7d4a609cb352 100644 (file)
@@ -47,6 +47,13 @@ int dpp_prepare_channel_list(struct dpp_authentication *auth,
 void dpp_auth_fail(struct dpp_authentication *auth, const char *txt);
 int dpp_gen_uri(struct dpp_bootstrap_info *bi);
 
+/* dpp_backup.c */
+
+void dpp_free_asymmetric_key(struct dpp_asymmetric_key *key);
+struct wpabuf * dpp_build_enveloped_data(struct dpp_authentication *auth);
+int dpp_conf_resp_env_data(struct dpp_authentication *auth,
+                          const u8 *env_data, size_t env_data_len);
+
 /* dpp_crypto.c */
 
 struct dpp_signed_connector_info {
index 3b49fa4f5cefff9e9fd2c81480579a91323df3ae..a5c45fd903773c61c2628a151bfad8f4b46301a2 100644 (file)
@@ -22,6 +22,7 @@ OBJS += $(SRC)/crypto/sha512-kdf.o
 OBJS += $(SRC)/tls/asn1.o
 OBJS += $(SRC)/common/dpp.o
 OBJS += $(SRC)/common/dpp_auth.o
+OBJS += $(SRC)/common/dpp_backup.o
 OBJS += $(SRC)/common/dpp_crypto.o
 OBJS += $(SRC)/common/dpp_pkex.o
 OBJS += $(SRC)/common/dpp_reconfig.o
index c85e7f9573aab58f688ec5480b7c48b9bd35ba10..eea5875e07e68f0a94ee8594f853861fed42b3e0 100644 (file)
@@ -248,6 +248,7 @@ ifdef CONFIG_DPP
 L_CFLAGS += -DCONFIG_DPP
 OBJS += src/common/dpp.c
 OBJS += src/common/dpp_auth.c
+OBJS += src/common/dpp_backup.c
 OBJS += src/common/dpp_crypto.c
 OBJS += src/common/dpp_pkex.c
 OBJS += src/common/dpp_reconfig.c
index 34ac16472fbde1c631f6db4b722b2f65674ced86..66ed8352ad5de6489f93d7a752fbb13aa72029d2 100644 (file)
@@ -280,6 +280,7 @@ ifdef CONFIG_DPP
 CFLAGS += -DCONFIG_DPP
 OBJS += ../src/common/dpp.o
 OBJS += ../src/common/dpp_auth.o
+OBJS += ../src/common/dpp_backup.o
 OBJS += ../src/common/dpp_crypto.o
 OBJS += ../src/common/dpp_pkex.o
 OBJS += ../src/common/dpp_reconfig.o