1 /* 2 * DPP configurator backup 3 * Copyright (c) 2019-2020, The Linux Foundation 4 * 5 * This software may be distributed under the terms of the BSD license. 6 * See README for more details. 7 */ 8 9 #include "utils/includes.h" 10 11 #include "utils/common.h" 12 #include "crypto/aes.h" 13 #include "crypto/aes_siv.h" 14 #include "tls/asn1.h" 15 #include "dpp.h" 16 #include "dpp_i.h" 17 18 #ifdef CONFIG_DPP2 19 20 void dpp_free_asymmetric_key(struct dpp_asymmetric_key *key) 21 { 22 while (key) { 23 struct dpp_asymmetric_key *next = key->next; 24 25 crypto_ec_key_deinit(key->csign); 26 crypto_ec_key_deinit(key->pp_key); 27 str_clear_free(key->config_template); 28 str_clear_free(key->connector_template); 29 os_free(key); 30 key = next; 31 } 32 } 33 34 35 static struct wpabuf * dpp_build_conf_params(struct dpp_configurator *conf) 36 { 37 struct wpabuf *buf, *priv_key = NULL; 38 size_t len; 39 /* TODO: proper template values */ 40 const char *conf_template = "{\"wi-fi_tech\":\"infra\",\"discovery\":{\"ssid\":\"test\"},\"cred\":{\"akm\":\"dpp\"}}"; 41 const char *connector_template = NULL; 42 43 if (!conf->pp_key) 44 return NULL; 45 46 priv_key = crypto_ec_key_get_ecprivate_key(conf->pp_key, false); 47 if (!priv_key) 48 return NULL; 49 50 len = 100 + os_strlen(conf_template); 51 if (connector_template) 52 len += os_strlen(connector_template); 53 if (priv_key) 54 len += wpabuf_len(priv_key); 55 buf = wpabuf_alloc(len); 56 if (!buf) 57 goto fail; 58 59 /* 60 * DPPConfigurationParameters ::= SEQUENCE { 61 * privacyProtectionKey PrivateKey, 62 * configurationTemplate UTF8String, 63 * connectorTemplate UTF8String OPTIONAL} 64 */ 65 66 /* PrivateKey ::= OCTET STRING */ 67 asn1_put_octet_string(buf, priv_key); 68 69 asn1_put_utf8string(buf, conf_template); 70 if (connector_template) 71 asn1_put_utf8string(buf, connector_template); 72 wpabuf_clear_free(priv_key); 73 return asn1_encaps(buf, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE); 74 fail: 75 wpabuf_clear_free(priv_key); 76 return NULL; 77 } 78 79 80 static struct wpabuf * dpp_build_attribute(struct dpp_configurator *conf) 81 { 82 struct wpabuf *conf_params, *attr; 83 84 /* 85 * aa-DPPConfigurationParameters ATTRIBUTE ::= 86 * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams } 87 * 88 * Attribute ::= SEQUENCE { 89 * type OBJECT IDENTIFIER, 90 * values SET SIZE(1..MAX) OF Type 91 */ 92 conf_params = dpp_build_conf_params(conf); 93 conf_params = asn1_encaps(conf_params, ASN1_CLASS_UNIVERSAL, 94 ASN1_TAG_SET); 95 if (!conf_params) 96 return NULL; 97 98 attr = wpabuf_alloc(100 + wpabuf_len(conf_params)); 99 if (!attr) { 100 wpabuf_clear_free(conf_params); 101 return NULL; 102 } 103 104 asn1_put_oid(attr, &asn1_dpp_config_params_oid); 105 wpabuf_put_buf(attr, conf_params); 106 wpabuf_clear_free(conf_params); 107 108 return asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE); 109 } 110 111 112 static struct wpabuf * dpp_build_key_alg(const struct dpp_curve_params *curve) 113 { 114 const struct asn1_oid *oid; 115 struct wpabuf *params, *res; 116 117 switch (curve->ike_group) { 118 case 19: 119 oid = &asn1_prime256v1_oid; 120 break; 121 case 20: 122 oid = &asn1_secp384r1_oid; 123 break; 124 case 21: 125 oid = &asn1_secp521r1_oid; 126 break; 127 case 28: 128 oid = &asn1_brainpoolP256r1_oid; 129 break; 130 case 29: 131 oid = &asn1_brainpoolP384r1_oid; 132 break; 133 case 30: 134 oid = &asn1_brainpoolP512r1_oid; 135 break; 136 default: 137 return NULL; 138 } 139 140 params = wpabuf_alloc(20); 141 if (!params) 142 return NULL; 143 asn1_put_oid(params, oid); /* namedCurve */ 144 145 res = asn1_build_alg_id(&asn1_ec_public_key_oid, params); 146 wpabuf_free(params); 147 return res; 148 } 149 150 151 static struct wpabuf * dpp_build_key_pkg(struct dpp_authentication *auth) 152 { 153 struct wpabuf *key = NULL, *attr, *alg, *priv_key = NULL; 154 155 priv_key = crypto_ec_key_get_ecprivate_key(auth->conf->csign, false); 156 if (!priv_key) 157 return NULL; 158 159 alg = dpp_build_key_alg(auth->conf->curve); 160 161 /* Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } */ 162 attr = dpp_build_attribute(auth->conf); 163 attr = asn1_encaps(attr, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SET); 164 if (!priv_key || !attr || !alg) 165 goto fail; 166 167 /* 168 * OneAsymmetricKey ::= SEQUENCE { 169 * version Version, 170 * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, 171 * privateKey PrivateKey, 172 * attributes [0] Attributes OPTIONAL, 173 * ..., 174 * [[2: publicKey [1] BIT STRING OPTIONAL ]], 175 * ... 176 * } 177 */ 178 179 key = wpabuf_alloc(100 + wpabuf_len(alg) + wpabuf_len(priv_key) + 180 wpabuf_len(attr)); 181 if (!key) 182 goto fail; 183 184 asn1_put_integer(key, 0); /* version = v1(0) */ 185 186 /* PrivateKeyAlgorithmIdentifier */ 187 wpabuf_put_buf(key, alg); 188 189 /* PrivateKey ::= OCTET STRING */ 190 asn1_put_octet_string(key, priv_key); 191 192 /* [0] Attributes OPTIONAL */ 193 asn1_put_hdr(key, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0, wpabuf_len(attr)); 194 wpabuf_put_buf(key, attr); 195 196 fail: 197 wpabuf_clear_free(attr); 198 wpabuf_clear_free(priv_key); 199 wpabuf_free(alg); 200 201 /* 202 * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage 203 * 204 * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey 205 * 206 * OneAsymmetricKey ::= SEQUENCE 207 */ 208 return asn1_encaps(asn1_encaps(key, 209 ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE), 210 ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE); 211 } 212 213 214 static struct wpabuf * dpp_build_pbkdf2_alg_id(const struct wpabuf *salt, 215 size_t hash_len) 216 { 217 struct wpabuf *params = NULL, *buf = NULL, *prf = NULL; 218 const struct asn1_oid *oid; 219 220 /* 221 * PBKDF2-params ::= SEQUENCE { 222 * salt CHOICE { 223 * specified OCTET STRING, 224 * otherSource AlgorithmIdentifier} 225 * iterationCount INTEGER (1..MAX), 226 * keyLength INTEGER (1..MAX), 227 * prf AlgorithmIdentifier} 228 * 229 * salt is an 64 octet value, iterationCount is 1000, keyLength is based 230 * on Configurator signing key length, prf is 231 * id-hmacWithSHA{256,384,512} based on Configurator signing key. 232 */ 233 234 if (hash_len == 32) 235 oid = &asn1_pbkdf2_hmac_sha256_oid; 236 else if (hash_len == 48) 237 oid = &asn1_pbkdf2_hmac_sha384_oid; 238 else if (hash_len == 64) 239 oid = &asn1_pbkdf2_hmac_sha512_oid; 240 else 241 goto fail; 242 prf = asn1_build_alg_id(oid, NULL); 243 if (!prf) 244 goto fail; 245 params = wpabuf_alloc(100 + wpabuf_len(salt) + wpabuf_len(prf)); 246 if (!params) 247 goto fail; 248 asn1_put_octet_string(params, salt); /* salt.specified */ 249 asn1_put_integer(params, 1000); /* iterationCount */ 250 asn1_put_integer(params, hash_len); /* keyLength */ 251 wpabuf_put_buf(params, prf); 252 params = asn1_encaps(params, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE); 253 if (!params) 254 goto fail; 255 buf = asn1_build_alg_id(&asn1_pbkdf2_oid, params); 256 fail: 257 wpabuf_free(params); 258 wpabuf_free(prf); 259 return buf; 260 } 261 262 263 static struct wpabuf * 264 dpp_build_pw_recipient_info(struct dpp_authentication *auth, size_t hash_len, 265 const struct wpabuf *cont_enc_key) 266 { 267 struct wpabuf *pwri = NULL, *enc_key = NULL, *key_der_alg = NULL, 268 *key_enc_alg = NULL, *salt; 269 u8 kek[DPP_MAX_HASH_LEN]; 270 u8 key[DPP_MAX_HASH_LEN]; 271 size_t key_len; 272 int res; 273 274 salt = wpabuf_alloc(64); 275 if (!salt || os_get_random(wpabuf_put(salt, 64), 64) < 0) 276 goto fail; 277 wpa_hexdump_buf(MSG_DEBUG, "DPP: PBKDF2 salt", salt); 278 279 key_len = auth->curve->hash_len; 280 /* password = HKDF-Expand(bk, "Enveloped Data Password", length) */ 281 res = dpp_hkdf_expand(key_len, auth->bk, key_len, 282 "Enveloped Data Password", key, key_len); 283 if (res < 0) 284 goto fail; 285 wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len); 286 287 if (dpp_pbkdf2(hash_len, key, key_len, wpabuf_head(salt), 64, 1000, 288 kek, hash_len)) { 289 wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed"); 290 goto fail; 291 } 292 wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2", 293 kek, hash_len); 294 295 enc_key = wpabuf_alloc(hash_len + AES_BLOCK_SIZE); 296 if (!enc_key || 297 aes_siv_encrypt(kek, hash_len, wpabuf_head(cont_enc_key), 298 wpabuf_len(cont_enc_key), 0, NULL, NULL, 299 wpabuf_put(enc_key, hash_len + AES_BLOCK_SIZE)) < 0) 300 goto fail; 301 wpa_hexdump_buf(MSG_DEBUG, "DPP: encryptedKey", enc_key); 302 303 /* 304 * PasswordRecipientInfo ::= SEQUENCE { 305 * version CMSVersion, 306 * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL, 307 * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, 308 * encryptedKey EncryptedKey} 309 * 310 * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the 311 * parameters contains PBKDF2-params SEQUENCE. 312 */ 313 314 key_der_alg = dpp_build_pbkdf2_alg_id(salt, hash_len); 315 key_enc_alg = asn1_build_alg_id(&asn1_aes_siv_cmac_aead_256_oid, NULL); 316 if (!key_der_alg || !key_enc_alg) 317 goto fail; 318 pwri = wpabuf_alloc(100 + wpabuf_len(key_der_alg) + 319 wpabuf_len(key_enc_alg) + wpabuf_len(enc_key)); 320 if (!pwri) 321 goto fail; 322 323 /* version = 0 */ 324 asn1_put_integer(pwri, 0); 325 326 /* [0] KeyDerivationAlgorithmIdentifier */ 327 asn1_put_hdr(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 1, 0, 328 wpabuf_len(key_der_alg)); 329 wpabuf_put_buf(pwri, key_der_alg); 330 331 /* KeyEncryptionAlgorithmIdentifier */ 332 wpabuf_put_buf(pwri, key_enc_alg); 333 334 /* EncryptedKey ::= OCTET STRING */ 335 asn1_put_octet_string(pwri, enc_key); 336 337 fail: 338 wpabuf_clear_free(key_der_alg); 339 wpabuf_free(key_enc_alg); 340 wpabuf_free(enc_key); 341 wpabuf_free(salt); 342 forced_memzero(kek, sizeof(kek)); 343 return asn1_encaps(pwri, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE); 344 } 345 346 347 static struct wpabuf * 348 dpp_build_recipient_info(struct dpp_authentication *auth, size_t hash_len, 349 const struct wpabuf *cont_enc_key) 350 { 351 struct wpabuf *pwri; 352 353 /* 354 * RecipientInfo ::= CHOICE { 355 * ktri KeyTransRecipientInfo, 356 * kari [1] KeyAgreeRecipientInfo, 357 * kekri [2] KEKRecipientInfo, 358 * pwri [3] PasswordRecipientInfo, 359 * ori [4] OtherRecipientInfo} 360 * 361 * Shall always use the pwri CHOICE. 362 */ 363 364 pwri = dpp_build_pw_recipient_info(auth, hash_len, cont_enc_key); 365 return asn1_encaps(pwri, ASN1_CLASS_CONTEXT_SPECIFIC, 3); 366 } 367 368 369 static struct wpabuf * 370 dpp_build_enc_cont_info(struct dpp_authentication *auth, size_t hash_len, 371 const struct wpabuf *cont_enc_key) 372 { 373 struct wpabuf *key_pkg, *enc_cont_info = NULL, *enc_cont = NULL, 374 *enc_alg; 375 const struct asn1_oid *oid; 376 size_t enc_cont_len; 377 378 /* 379 * EncryptedContentInfo ::= SEQUENCE { 380 * contentType ContentType, 381 * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, 382 * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL} 383 */ 384 385 if (hash_len == 32) 386 oid = &asn1_aes_siv_cmac_aead_256_oid; 387 else if (hash_len == 48) 388 oid = &asn1_aes_siv_cmac_aead_384_oid; 389 else if (hash_len == 64) 390 oid = &asn1_aes_siv_cmac_aead_512_oid; 391 else 392 return NULL; 393 394 key_pkg = dpp_build_key_pkg(auth); 395 enc_alg = asn1_build_alg_id(oid, NULL); 396 if (!key_pkg || !enc_alg) 397 goto fail; 398 399 wpa_hexdump_buf_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage", 400 key_pkg); 401 402 enc_cont_len = wpabuf_len(key_pkg) + AES_BLOCK_SIZE; 403 enc_cont = wpabuf_alloc(enc_cont_len); 404 if (!enc_cont || 405 aes_siv_encrypt(wpabuf_head(cont_enc_key), wpabuf_len(cont_enc_key), 406 wpabuf_head(key_pkg), wpabuf_len(key_pkg), 407 0, NULL, NULL, 408 wpabuf_put(enc_cont, enc_cont_len)) < 0) 409 goto fail; 410 411 enc_cont_info = wpabuf_alloc(100 + wpabuf_len(enc_alg) + 412 wpabuf_len(enc_cont)); 413 if (!enc_cont_info) 414 goto fail; 415 416 /* ContentType ::= OBJECT IDENTIFIER */ 417 asn1_put_oid(enc_cont_info, &asn1_dpp_asymmetric_key_package_oid); 418 419 /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */ 420 wpabuf_put_buf(enc_cont_info, enc_alg); 421 422 /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL 423 * EncryptedContent ::= OCTET STRING */ 424 asn1_put_hdr(enc_cont_info, ASN1_CLASS_CONTEXT_SPECIFIC, 0, 0, 425 wpabuf_len(enc_cont)); 426 wpabuf_put_buf(enc_cont_info, enc_cont); 427 428 fail: 429 wpabuf_clear_free(key_pkg); 430 wpabuf_free(enc_cont); 431 wpabuf_free(enc_alg); 432 return enc_cont_info; 433 } 434 435 436 static struct wpabuf * dpp_gen_random(size_t len) 437 { 438 struct wpabuf *key; 439 440 key = wpabuf_alloc(len); 441 if (!key || os_get_random(wpabuf_put(key, len), len) < 0) { 442 wpabuf_free(key); 443 key = NULL; 444 } 445 wpa_hexdump_buf_key(MSG_DEBUG, "DPP: content-encryption key", key); 446 return key; 447 } 448 449 450 struct wpabuf * dpp_build_enveloped_data(struct dpp_authentication *auth) 451 { 452 struct wpabuf *env = NULL; 453 struct wpabuf *recipient_info = NULL, *enc_cont_info = NULL; 454 struct wpabuf *cont_enc_key = NULL; 455 size_t hash_len; 456 457 if (!auth->conf) { 458 wpa_printf(MSG_DEBUG, 459 "DPP: No Configurator instance selected for the session - cannot build DPPEnvelopedData"); 460 return NULL; 461 } 462 463 if (!auth->provision_configurator) { 464 wpa_printf(MSG_DEBUG, 465 "DPP: Configurator provisioning not allowed"); 466 return NULL; 467 } 468 469 wpa_printf(MSG_DEBUG, "DPP: Building DPPEnvelopedData"); 470 471 hash_len = auth->conf->curve->hash_len; 472 cont_enc_key = dpp_gen_random(hash_len); 473 if (!cont_enc_key) 474 goto fail; 475 recipient_info = dpp_build_recipient_info(auth, hash_len, cont_enc_key); 476 enc_cont_info = dpp_build_enc_cont_info(auth, hash_len, cont_enc_key); 477 if (!recipient_info || !enc_cont_info) 478 goto fail; 479 480 env = wpabuf_alloc(wpabuf_len(recipient_info) + 481 wpabuf_len(enc_cont_info) + 482 100); 483 if (!env) 484 goto fail; 485 486 /* 487 * DPPEnvelopedData ::= EnvelopedData 488 * 489 * EnvelopedData ::= SEQUENCE { 490 * version CMSVersion, 491 * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, 492 * recipientInfos RecipientInfos, 493 * encryptedContentInfo EncryptedContentInfo, 494 * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL} 495 * 496 * For DPP, version is 3, both originatorInfo and 497 * unprotectedAttrs are omitted, and recipientInfos contains a single 498 * RecipientInfo. 499 */ 500 501 /* EnvelopedData.version = 3 */ 502 asn1_put_integer(env, 3); 503 504 /* RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo */ 505 asn1_put_set(env, recipient_info); 506 507 /* EncryptedContentInfo ::= SEQUENCE */ 508 asn1_put_sequence(env, enc_cont_info); 509 510 env = asn1_encaps(env, ASN1_CLASS_UNIVERSAL, ASN1_TAG_SEQUENCE); 511 wpa_hexdump_buf(MSG_MSGDUMP, "DPP: DPPEnvelopedData", env); 512 out: 513 wpabuf_clear_free(cont_enc_key); 514 wpabuf_clear_free(recipient_info); 515 wpabuf_free(enc_cont_info); 516 return env; 517 fail: 518 wpabuf_free(env); 519 env = NULL; 520 goto out; 521 } 522 523 524 struct dpp_enveloped_data { 525 const u8 *enc_cont; 526 size_t enc_cont_len; 527 const u8 *enc_key; 528 size_t enc_key_len; 529 const u8 *salt; 530 size_t pbkdf2_key_len; 531 size_t prf_hash_len; 532 }; 533 534 535 static int dpp_parse_recipient_infos(const u8 *pos, size_t len, 536 struct dpp_enveloped_data *data) 537 { 538 struct asn1_hdr hdr; 539 const u8 *end = pos + len; 540 const u8 *next, *e_end; 541 struct asn1_oid oid; 542 int val; 543 const u8 *params; 544 size_t params_len; 545 546 wpa_hexdump(MSG_MSGDUMP, "DPP: RecipientInfos", pos, len); 547 548 /* 549 * RecipientInfo ::= CHOICE { 550 * ktri KeyTransRecipientInfo, 551 * kari [1] KeyAgreeRecipientInfo, 552 * kekri [2] KEKRecipientInfo, 553 * pwri [3] PasswordRecipientInfo, 554 * ori [4] OtherRecipientInfo} 555 * 556 * Shall always use the pwri CHOICE. 557 */ 558 559 if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed || 560 !asn1_is_cs_tag(&hdr, 3)) { 561 asn1_unexpected(&hdr, "DPP: Expected CHOICE [3] (pwri)"); 562 return -1; 563 } 564 wpa_hexdump(MSG_MSGDUMP, "DPP: PasswordRecipientInfo", 565 hdr.payload, hdr.length); 566 pos = hdr.payload; 567 end = pos + hdr.length; 568 569 /* 570 * PasswordRecipientInfo ::= SEQUENCE { 571 * version CMSVersion, 572 * keyDerivationAlgorithm [0] KeyDerivationAlgorithmIdentifier OPTIONAL, 573 * keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier, 574 * encryptedKey EncryptedKey} 575 * 576 * version is 0, keyDerivationAlgorithm is id-PKBDF2, and the 577 * parameters contains PBKDF2-params SEQUENCE. 578 */ 579 580 if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0) 581 return -1; 582 pos = hdr.payload; 583 584 if (asn1_get_integer(pos, end - pos, &val, &pos) < 0) 585 return -1; 586 if (val != 0) { 587 wpa_printf(MSG_DEBUG, "DPP: pwri.version != 0"); 588 return -1; 589 } 590 591 wpa_hexdump(MSG_MSGDUMP, "DPP: Remaining PasswordRecipientInfo after version", 592 pos, end - pos); 593 594 if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed || 595 !asn1_is_cs_tag(&hdr, 0)) { 596 asn1_unexpected(&hdr, 597 "DPP: Expected keyDerivationAlgorithm [0]"); 598 return -1; 599 } 600 pos = hdr.payload; 601 e_end = pos + hdr.length; 602 603 /* KeyDerivationAlgorithmIdentifier ::= AlgorithmIdentifier */ 604 if (asn1_get_alg_id(pos, e_end - pos, &oid, ¶ms, ¶ms_len, 605 &next) < 0) 606 return -1; 607 if (!asn1_oid_equal(&oid, &asn1_pbkdf2_oid)) { 608 char buf[80]; 609 610 asn1_oid_to_str(&oid, buf, sizeof(buf)); 611 wpa_printf(MSG_DEBUG, 612 "DPP: Unexpected KeyDerivationAlgorithmIdentifier %s", 613 buf); 614 return -1; 615 } 616 617 /* 618 * PBKDF2-params ::= SEQUENCE { 619 * salt CHOICE { 620 * specified OCTET STRING, 621 * otherSource AlgorithmIdentifier} 622 * iterationCount INTEGER (1..MAX), 623 * keyLength INTEGER (1..MAX), 624 * prf AlgorithmIdentifier} 625 * 626 * salt is an 64 octet value, iterationCount is 1000, keyLength is based 627 * on Configurator signing key length, prf is 628 * id-hmacWithSHA{256,384,512} based on Configurator signing key. 629 */ 630 if (!params || 631 asn1_get_sequence(params, params_len, &hdr, &e_end) < 0) 632 return -1; 633 pos = hdr.payload; 634 635 if (asn1_get_next(pos, e_end - pos, &hdr) < 0 || 636 !asn1_is_octetstring(&hdr)) { 637 asn1_unexpected(&hdr, 638 "DPP: Expected OCTETSTRING (salt.specified)"); 639 return -1; 640 } 641 wpa_hexdump(MSG_MSGDUMP, "DPP: salt.specified", 642 hdr.payload, hdr.length); 643 if (hdr.length != 64) { 644 wpa_printf(MSG_DEBUG, "DPP: Unexpected salt length %u", 645 hdr.length); 646 return -1; 647 } 648 data->salt = hdr.payload; 649 pos = hdr.payload + hdr.length; 650 651 if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0) 652 return -1; 653 if (val != 1000) { 654 wpa_printf(MSG_DEBUG, "DPP: Unexpected iterationCount %d", val); 655 return -1; 656 } 657 658 if (asn1_get_integer(pos, e_end - pos, &val, &pos) < 0) 659 return -1; 660 if (val != 32 && val != 48 && val != 64) { 661 wpa_printf(MSG_DEBUG, "DPP: Unexpected keyLength %d", val); 662 return -1; 663 } 664 data->pbkdf2_key_len = val; 665 666 if (asn1_get_sequence(pos, e_end - pos, &hdr, NULL) < 0 || 667 asn1_get_oid(hdr.payload, hdr.length, &oid, &pos) < 0) { 668 wpa_printf(MSG_DEBUG, "DPP: Could not parse prf"); 669 return -1; 670 } 671 if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha256_oid)) { 672 data->prf_hash_len = 32; 673 } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha384_oid)) { 674 data->prf_hash_len = 48; 675 } else if (asn1_oid_equal(&oid, &asn1_pbkdf2_hmac_sha512_oid)) { 676 data->prf_hash_len = 64; 677 } else { 678 char buf[80]; 679 680 asn1_oid_to_str(&oid, buf, sizeof(buf)); 681 wpa_printf(MSG_DEBUG, "DPP: Unexpected PBKDF2-params.prf %s", 682 buf); 683 return -1; 684 } 685 686 pos = next; 687 688 /* keyEncryptionAlgorithm KeyEncryptionAlgorithmIdentifier 689 * 690 * KeyEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier 691 * 692 * id-alg-AES-SIV-CMAC-aed-256, id-alg-AES-SIV-CMAC-aed-384, or 693 * id-alg-AES-SIV-CMAC-aed-512. */ 694 if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0) 695 return -1; 696 if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) && 697 !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) && 698 !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) { 699 char buf[80]; 700 701 asn1_oid_to_str(&oid, buf, sizeof(buf)); 702 wpa_printf(MSG_DEBUG, 703 "DPP: Unexpected KeyEncryptionAlgorithmIdentifier %s", 704 buf); 705 return -1; 706 } 707 708 /* 709 * encryptedKey EncryptedKey 710 * 711 * EncryptedKey ::= OCTET STRING 712 */ 713 if (asn1_get_next(pos, end - pos, &hdr) < 0 || 714 !asn1_is_octetstring(&hdr)) { 715 asn1_unexpected(&hdr, 716 "DPP: Expected OCTETSTRING (pwri.encryptedKey)"); 717 return -1; 718 } 719 wpa_hexdump(MSG_MSGDUMP, "DPP: pwri.encryptedKey", 720 hdr.payload, hdr.length); 721 data->enc_key = hdr.payload; 722 data->enc_key_len = hdr.length; 723 724 return 0; 725 } 726 727 728 static int dpp_parse_encrypted_content_info(const u8 *pos, const u8 *end, 729 struct dpp_enveloped_data *data) 730 { 731 struct asn1_hdr hdr; 732 struct asn1_oid oid; 733 734 /* 735 * EncryptedContentInfo ::= SEQUENCE { 736 * contentType ContentType, 737 * contentEncryptionAlgorithm ContentEncryptionAlgorithmIdentifier, 738 * encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL} 739 */ 740 if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0) 741 return -1; 742 wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContentInfo", 743 hdr.payload, hdr.length); 744 if (pos < end) { 745 wpa_hexdump(MSG_DEBUG, 746 "DPP: Unexpected extra data after EncryptedContentInfo", 747 pos, end - pos); 748 return -1; 749 } 750 751 end = pos; 752 pos = hdr.payload; 753 754 /* ContentType ::= OBJECT IDENTIFIER */ 755 if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) { 756 wpa_printf(MSG_DEBUG, "DPP: Could not parse ContentType"); 757 return -1; 758 } 759 if (!asn1_oid_equal(&oid, &asn1_dpp_asymmetric_key_package_oid)) { 760 char buf[80]; 761 762 asn1_oid_to_str(&oid, buf, sizeof(buf)); 763 wpa_printf(MSG_DEBUG, "DPP: Unexpected ContentType %s", buf); 764 return -1; 765 } 766 767 /* ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier */ 768 if (asn1_get_alg_id(pos, end - pos, &oid, NULL, NULL, &pos) < 0) 769 return -1; 770 if (!asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_256_oid) && 771 !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_384_oid) && 772 !asn1_oid_equal(&oid, &asn1_aes_siv_cmac_aead_512_oid)) { 773 char buf[80]; 774 775 asn1_oid_to_str(&oid, buf, sizeof(buf)); 776 wpa_printf(MSG_DEBUG, 777 "DPP: Unexpected ContentEncryptionAlgorithmIdentifier %s", 778 buf); 779 return -1; 780 } 781 /* ignore optional parameters */ 782 783 /* encryptedContent [0] IMPLICIT EncryptedContent OPTIONAL 784 * EncryptedContent ::= OCTET STRING */ 785 if (asn1_get_next(pos, end - pos, &hdr) < 0 || hdr.constructed || 786 !asn1_is_cs_tag(&hdr, 0)) { 787 asn1_unexpected(&hdr, 788 "DPP: Expected [0] IMPLICIT (EncryptedContent)"); 789 return -1; 790 } 791 wpa_hexdump(MSG_MSGDUMP, "DPP: EncryptedContent", 792 hdr.payload, hdr.length); 793 data->enc_cont = hdr.payload; 794 data->enc_cont_len = hdr.length; 795 return 0; 796 } 797 798 799 static int dpp_parse_enveloped_data(const u8 *env_data, size_t env_data_len, 800 struct dpp_enveloped_data *data) 801 { 802 struct asn1_hdr hdr; 803 const u8 *pos, *end; 804 int val; 805 806 os_memset(data, 0, sizeof(*data)); 807 808 /* 809 * DPPEnvelopedData ::= EnvelopedData 810 * 811 * EnvelopedData ::= SEQUENCE { 812 * version CMSVersion, 813 * originatorInfo [0] IMPLICIT OriginatorInfo OPTIONAL, 814 * recipientInfos RecipientInfos, 815 * encryptedContentInfo EncryptedContentInfo, 816 * unprotectedAttrs [1] IMPLICIT UnprotectedAttributes OPTIONAL} 817 * 818 * CMSVersion ::= INTEGER 819 * 820 * RecipientInfos ::= SET SIZE (1..MAX) OF RecipientInfo 821 * 822 * For DPP, version is 3, both originatorInfo and 823 * unprotectedAttrs are omitted, and recipientInfos contains a single 824 * RecipientInfo. 825 */ 826 if (asn1_get_sequence(env_data, env_data_len, &hdr, &end) < 0) 827 return -1; 828 pos = hdr.payload; 829 if (end < env_data + env_data_len) { 830 wpa_hexdump(MSG_DEBUG, 831 "DPP: Unexpected extra data after DPPEnvelopedData", 832 end, env_data + env_data_len - end); 833 return -1; 834 } 835 836 if (asn1_get_integer(pos, end - pos, &val, &pos) < 0) 837 return -1; 838 if (val != 3) { 839 wpa_printf(MSG_DEBUG, "DPP: EnvelopedData.version != 3"); 840 return -1; 841 } 842 843 if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_set(&hdr)) { 844 asn1_unexpected(&hdr, 845 "DPP: Expected SET (RecipientInfos)"); 846 return -1; 847 } 848 849 if (dpp_parse_recipient_infos(hdr.payload, hdr.length, data) < 0) 850 return -1; 851 return dpp_parse_encrypted_content_info(hdr.payload + hdr.length, end, 852 data); 853 } 854 855 856 static struct dpp_asymmetric_key * 857 dpp_parse_one_asymmetric_key(const u8 *buf, size_t len) 858 { 859 struct asn1_hdr hdr; 860 const u8 *pos = buf, *end = buf + len, *next; 861 int val; 862 const u8 *params; 863 size_t params_len; 864 struct asn1_oid oid; 865 char txt[80]; 866 struct dpp_asymmetric_key *key; 867 868 wpa_hexdump_key(MSG_MSGDUMP, "DPP: OneAsymmetricKey", buf, len); 869 870 key = os_zalloc(sizeof(*key)); 871 if (!key) 872 return NULL; 873 874 /* 875 * OneAsymmetricKey ::= SEQUENCE { 876 * version Version, 877 * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier, 878 * privateKey PrivateKey, 879 * attributes [0] Attributes OPTIONAL, 880 * ..., 881 * [[2: publicKey [1] BIT STRING OPTIONAL ]], 882 * ... 883 * } 884 */ 885 if (asn1_get_sequence(pos, end - pos, &hdr, &end) < 0) 886 goto fail; 887 pos = hdr.payload; 888 889 /* Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2) */ 890 if (asn1_get_integer(pos, end - pos, &val, &pos) < 0) 891 goto fail; 892 if (val != 0 && val != 1) { 893 wpa_printf(MSG_DEBUG, 894 "DPP: Unsupported DPPAsymmetricKeyPackage version %d", 895 val); 896 goto fail; 897 } 898 899 /* PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier */ 900 if (asn1_get_alg_id(pos, end - pos, &oid, ¶ms, ¶ms_len, 901 &pos) < 0) 902 goto fail; 903 if (!asn1_oid_equal(&oid, &asn1_ec_public_key_oid)) { 904 asn1_oid_to_str(&oid, txt, sizeof(txt)); 905 wpa_printf(MSG_DEBUG, 906 "DPP: Unsupported PrivateKeyAlgorithmIdentifier %s", 907 txt); 908 goto fail; 909 } 910 wpa_hexdump(MSG_MSGDUMP, "DPP: PrivateKeyAlgorithmIdentifier params", 911 params, params_len); 912 /* 913 * ECParameters ::= CHOICE { 914 * namedCurve OBJECT IDENTIFIER 915 * -- implicitCurve NULL 916 * -- specifiedCurve SpecifiedECDomain} 917 */ 918 if (!params || asn1_get_oid(params, params_len, &oid, &next) < 0) { 919 wpa_printf(MSG_DEBUG, 920 "DPP: Could not parse ECParameters.namedCurve"); 921 goto fail; 922 } 923 asn1_oid_to_str(&oid, txt, sizeof(txt)); 924 wpa_printf(MSG_MSGDUMP, "DPP: namedCurve %s", txt); 925 /* Assume the curve is identified within ECPrivateKey, so that this 926 * separate indication is not really needed. */ 927 928 /* 929 * PrivateKey ::= OCTET STRING 930 * (Contains DER encoding of ECPrivateKey) 931 */ 932 if (asn1_get_next(pos, end - pos, &hdr) < 0 || 933 !asn1_is_octetstring(&hdr)) { 934 asn1_unexpected(&hdr, 935 "DPP: Expected OCTETSTRING (PrivateKey)"); 936 goto fail; 937 } 938 wpa_hexdump_key(MSG_MSGDUMP, "DPP: PrivateKey", 939 hdr.payload, hdr.length); 940 pos = hdr.payload + hdr.length; 941 key->csign = crypto_ec_key_parse_priv(hdr.payload, hdr.length); 942 if (!key->csign) 943 goto fail; 944 if (wpa_debug_show_keys) 945 dpp_debug_print_key("DPP: Received c-sign-key", key->csign); 946 947 /* 948 * Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } } 949 * 950 * Exactly one instance of type Attribute in OneAsymmetricKey. 951 */ 952 if (asn1_get_next(pos, end - pos, &hdr) < 0 || !hdr.constructed || 953 !asn1_is_cs_tag(&hdr, 0)) { 954 asn1_unexpected(&hdr, "DPP: Expected [0] Attributes"); 955 goto fail; 956 } 957 wpa_hexdump_key(MSG_MSGDUMP, "DPP: Attributes", 958 hdr.payload, hdr.length); 959 if (hdr.payload + hdr.length < end) { 960 wpa_hexdump_key(MSG_MSGDUMP, 961 "DPP: Ignore additional data at the end of OneAsymmetricKey", 962 hdr.payload + hdr.length, 963 end - (hdr.payload + hdr.length)); 964 } 965 pos = hdr.payload; 966 end = hdr.payload + hdr.length; 967 968 if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_set(&hdr)) { 969 asn1_unexpected(&hdr, "DPP: Expected SET (Attributes)"); 970 goto fail; 971 } 972 if (hdr.payload + hdr.length < end) { 973 wpa_hexdump_key(MSG_MSGDUMP, 974 "DPP: Ignore additional data at the end of OneAsymmetricKey (after SET)", 975 hdr.payload + hdr.length, 976 end - (hdr.payload + hdr.length)); 977 } 978 pos = hdr.payload; 979 end = hdr.payload + hdr.length; 980 981 /* 982 * OneAsymmetricKeyAttributes ATTRIBUTE ::= { 983 * aa-DPPConfigurationParameters, 984 * ... -- For local profiles 985 * } 986 * 987 * aa-DPPConfigurationParameters ATTRIBUTE ::= 988 * { TYPE DPPConfigurationParameters IDENTIFIED BY id-DPPConfigParams } 989 * 990 * Attribute ::= SEQUENCE { 991 * type OBJECT IDENTIFIER, 992 * values SET SIZE(1..MAX) OF Type 993 * 994 * Exactly one instance of ATTRIBUTE in attrValues. 995 */ 996 if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0) 997 goto fail; 998 if (pos < end) { 999 wpa_hexdump_key(MSG_MSGDUMP, 1000 "DPP: Ignore additional data at the end of ATTRIBUTE", 1001 pos, end - pos); 1002 } 1003 end = pos; 1004 pos = hdr.payload; 1005 1006 if (asn1_get_oid(pos, end - pos, &oid, &pos) < 0) 1007 goto fail; 1008 if (!asn1_oid_equal(&oid, &asn1_dpp_config_params_oid)) { 1009 asn1_oid_to_str(&oid, txt, sizeof(txt)); 1010 wpa_printf(MSG_DEBUG, 1011 "DPP: Unexpected Attribute identifier %s", txt); 1012 goto fail; 1013 } 1014 1015 if (asn1_get_next(pos, end - pos, &hdr) < 0 || !asn1_is_set(&hdr)) { 1016 asn1_unexpected(&hdr, "DPP: Expected SET (Attribute)"); 1017 goto fail; 1018 } 1019 pos = hdr.payload; 1020 end = hdr.payload + hdr.length; 1021 1022 /* 1023 * DPPConfigurationParameters ::= SEQUENCE { 1024 * privacyProtectionKey PrivateKey, 1025 * configurationTemplate UTF8String, 1026 * connectorTemplate UTF8String OPTIONAL} 1027 */ 1028 1029 wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPConfigurationParameters", 1030 pos, end - pos); 1031 if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0) 1032 goto fail; 1033 if (pos < end) { 1034 wpa_hexdump_key(MSG_MSGDUMP, 1035 "DPP: Ignore additional data after DPPConfigurationParameters", 1036 pos, end - pos); 1037 } 1038 end = pos; 1039 pos = hdr.payload; 1040 1041 /* 1042 * PrivateKey ::= OCTET STRING 1043 * (Contains DER encoding of ECPrivateKey) 1044 */ 1045 if (asn1_get_next(pos, end - pos, &hdr) < 0 || 1046 !asn1_is_octetstring(&hdr)) { 1047 asn1_unexpected(&hdr, "DPP: Expected OCTETSTRING (PrivateKey)"); 1048 goto fail; 1049 } 1050 wpa_hexdump_key(MSG_MSGDUMP, "DPP: privacyProtectionKey", 1051 hdr.payload, hdr.length); 1052 pos = hdr.payload + hdr.length; 1053 key->pp_key = crypto_ec_key_parse_priv(hdr.payload, hdr.length); 1054 if (!key->pp_key) 1055 goto fail; 1056 if (wpa_debug_show_keys) 1057 dpp_debug_print_key("DPP: Received privacyProtectionKey", 1058 key->pp_key); 1059 1060 if (asn1_get_next(pos, end - pos, &hdr) < 0 || 1061 !asn1_is_utf8string(&hdr)) { 1062 asn1_unexpected(&hdr, 1063 "DPP: Expected UTF8STRING (configurationTemplate)"); 1064 goto fail; 1065 } 1066 wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: configurationTemplate", 1067 hdr.payload, hdr.length); 1068 key->config_template = os_zalloc(hdr.length + 1); 1069 if (!key->config_template) 1070 goto fail; 1071 os_memcpy(key->config_template, hdr.payload, hdr.length); 1072 1073 pos = hdr.payload + hdr.length; 1074 1075 if (pos < end) { 1076 if (asn1_get_next(pos, end - pos, &hdr) < 0 || 1077 !asn1_is_utf8string(&hdr)) { 1078 asn1_unexpected(&hdr, 1079 "DPP: Expected UTF8STRING (connectorTemplate)"); 1080 goto fail; 1081 } 1082 wpa_hexdump_ascii_key(MSG_MSGDUMP, "DPP: connectorTemplate", 1083 hdr.payload, hdr.length); 1084 key->connector_template = os_zalloc(hdr.length + 1); 1085 if (!key->connector_template) 1086 goto fail; 1087 os_memcpy(key->connector_template, hdr.payload, hdr.length); 1088 } 1089 1090 return key; 1091 fail: 1092 wpa_printf(MSG_DEBUG, "DPP: Failed to parse OneAsymmetricKey"); 1093 dpp_free_asymmetric_key(key); 1094 return NULL; 1095 } 1096 1097 1098 static struct dpp_asymmetric_key * 1099 dpp_parse_dpp_asymmetric_key_package(const u8 *key_pkg, size_t key_pkg_len) 1100 { 1101 struct asn1_hdr hdr; 1102 const u8 *pos = key_pkg, *end = key_pkg + key_pkg_len; 1103 struct dpp_asymmetric_key *first = NULL, *last = NULL, *key; 1104 1105 wpa_hexdump_key(MSG_MSGDUMP, "DPP: DPPAsymmetricKeyPackage", 1106 key_pkg, key_pkg_len); 1107 1108 /* 1109 * DPPAsymmetricKeyPackage ::= AsymmetricKeyPackage 1110 * 1111 * AsymmetricKeyPackage ::= SEQUENCE SIZE (1..MAX) OF OneAsymmetricKey 1112 */ 1113 while (pos < end) { 1114 if (asn1_get_sequence(pos, end - pos, &hdr, &pos) < 0 || 1115 !(key = dpp_parse_one_asymmetric_key(hdr.payload, 1116 hdr.length))) { 1117 dpp_free_asymmetric_key(first); 1118 return NULL; 1119 } 1120 if (!last) { 1121 first = last = key; 1122 } else { 1123 last->next = key; 1124 last = key; 1125 } 1126 } 1127 1128 return first; 1129 } 1130 1131 1132 int dpp_conf_resp_env_data(struct dpp_authentication *auth, 1133 const u8 *env_data, size_t env_data_len) 1134 { 1135 u8 key[DPP_MAX_HASH_LEN]; 1136 size_t key_len; 1137 u8 kek[DPP_MAX_HASH_LEN]; 1138 u8 cont_encr_key[DPP_MAX_HASH_LEN]; 1139 size_t cont_encr_key_len; 1140 int res; 1141 u8 *key_pkg; 1142 size_t key_pkg_len; 1143 struct dpp_enveloped_data data; 1144 struct dpp_asymmetric_key *keys; 1145 1146 wpa_hexdump(MSG_DEBUG, "DPP: DPPEnvelopedData", env_data, env_data_len); 1147 1148 if (dpp_parse_enveloped_data(env_data, env_data_len, &data) < 0) 1149 return -1; 1150 1151 key_len = auth->curve->hash_len; 1152 /* password = HKDF-Expand(bk, "Enveloped Data Password", length) */ 1153 res = dpp_hkdf_expand(key_len, auth->bk, key_len, 1154 "Enveloped Data Password", key, key_len); 1155 if (res < 0) 1156 return -1; 1157 wpa_hexdump_key(MSG_DEBUG, "DPP: PBKDF2 key", key, key_len); 1158 1159 if (dpp_pbkdf2(data.prf_hash_len, key, key_len, data.salt, 64, 1000, 1160 kek, data.pbkdf2_key_len)) { 1161 wpa_printf(MSG_DEBUG, "DPP: PBKDF2 failed"); 1162 return -1; 1163 } 1164 wpa_hexdump_key(MSG_DEBUG, "DPP: key-encryption key from PBKDF2", 1165 kek, data.pbkdf2_key_len); 1166 1167 if (data.enc_key_len < AES_BLOCK_SIZE || 1168 data.enc_key_len > sizeof(cont_encr_key) + AES_BLOCK_SIZE) { 1169 wpa_printf(MSG_DEBUG, "DPP: Invalid encryptedKey length"); 1170 return -1; 1171 } 1172 res = aes_siv_decrypt(kek, data.pbkdf2_key_len, 1173 data.enc_key, data.enc_key_len, 1174 0, NULL, NULL, cont_encr_key); 1175 forced_memzero(kek, data.pbkdf2_key_len); 1176 if (res < 0) { 1177 wpa_printf(MSG_DEBUG, 1178 "DPP: AES-SIV decryption of encryptedKey failed"); 1179 return -1; 1180 } 1181 cont_encr_key_len = data.enc_key_len - AES_BLOCK_SIZE; 1182 wpa_hexdump_key(MSG_DEBUG, "DPP: content-encryption key", 1183 cont_encr_key, cont_encr_key_len); 1184 1185 if (data.enc_cont_len < AES_BLOCK_SIZE) 1186 return -1; 1187 key_pkg_len = data.enc_cont_len - AES_BLOCK_SIZE; 1188 key_pkg = os_malloc(key_pkg_len); 1189 if (!key_pkg) 1190 return -1; 1191 res = aes_siv_decrypt(cont_encr_key, cont_encr_key_len, 1192 data.enc_cont, data.enc_cont_len, 1193 0, NULL, NULL, key_pkg); 1194 forced_memzero(cont_encr_key, cont_encr_key_len); 1195 if (res < 0) { 1196 bin_clear_free(key_pkg, key_pkg_len); 1197 wpa_printf(MSG_DEBUG, 1198 "DPP: AES-SIV decryption of encryptedContent failed"); 1199 return -1; 1200 } 1201 1202 keys = dpp_parse_dpp_asymmetric_key_package(key_pkg, key_pkg_len); 1203 bin_clear_free(key_pkg, key_pkg_len); 1204 dpp_free_asymmetric_key(auth->conf_key_pkg); 1205 auth->conf_key_pkg = keys; 1206 1207 return keys != NULL; 1208 } 1209 1210 #endif /* CONFIG_DPP2 */ 1211