1 /* 2 * DPP functionality shared between hostapd and wpa_supplicant 3 * Copyright (c) 2017, Qualcomm Atheros, Inc. 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 #include <openssl/opensslv.h> 11 #include <openssl/err.h> 12 13 #include "utils/common.h" 14 #include "utils/base64.h" 15 #include "utils/json.h" 16 #include "common/ieee802_11_common.h" 17 #include "common/ieee802_11_defs.h" 18 #include "common/wpa_ctrl.h" 19 #include "crypto/crypto.h" 20 #include "crypto/random.h" 21 #include "crypto/aes.h" 22 #include "crypto/aes_siv.h" 23 #include "crypto/sha384.h" 24 #include "crypto/sha512.h" 25 #include "dpp.h" 26 27 28 #if OPENSSL_VERSION_NUMBER < 0x10100000L 29 /* Compatibility wrappers for older versions. */ 30 31 static int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s) 32 { 33 sig->r = r; 34 sig->s = s; 35 return 1; 36 } 37 38 39 static void ECDSA_SIG_get0(const ECDSA_SIG *sig, const BIGNUM **pr, 40 const BIGNUM **ps) 41 { 42 if (pr) 43 *pr = sig->r; 44 if (ps) 45 *ps = sig->s; 46 } 47 48 #endif 49 50 51 static const struct dpp_curve_params dpp_curves[] = { 52 /* The mandatory to support and the default NIST P-256 curve needs to 53 * be the first entry on this list. */ 54 { "prime256v1", 32, 32, 16, 32, "P-256", 19, "ES256" }, 55 { "secp384r1", 48, 48, 24, 48, "P-384", 20, "ES384" }, 56 { "secp521r1", 64, 64, 32, 66, "P-521", 21, "ES512" }, 57 { "brainpoolP256r1", 32, 32, 16, 32, "BP-256", 28, "BS256" }, 58 { "brainpoolP384r1", 48, 48, 24, 48, "BP-384", 29, "BS384" }, 59 { "brainpoolP512r1", 64, 64, 32, 64, "BP-512", 30, "BS512" }, 60 { NULL, 0, 0, 0, 0, NULL, 0, NULL } 61 }; 62 63 64 /* Role-specific elements for PKEX */ 65 66 /* NIST P-256 */ 67 static const u8 pkex_init_x_p256[32] = { 68 0x56, 0x26, 0x12, 0xcf, 0x36, 0x48, 0xfe, 0x0b, 69 0x07, 0x04, 0xbb, 0x12, 0x22, 0x50, 0xb2, 0x54, 70 0xb1, 0x94, 0x64, 0x7e, 0x54, 0xce, 0x08, 0x07, 71 0x2e, 0xec, 0xca, 0x74, 0x5b, 0x61, 0x2d, 0x25 72 }; 73 static const u8 pkex_init_y_p256[32] = { 74 0x3e, 0x44, 0xc7, 0xc9, 0x8c, 0x1c, 0xa1, 0x0b, 75 0x20, 0x09, 0x93, 0xb2, 0xfd, 0xe5, 0x69, 0xdc, 76 0x75, 0xbc, 0xad, 0x33, 0xc1, 0xe7, 0xc6, 0x45, 77 0x4d, 0x10, 0x1e, 0x6a, 0x3d, 0x84, 0x3c, 0xa4 78 }; 79 static const u8 pkex_resp_x_p256[32] = { 80 0x1e, 0xa4, 0x8a, 0xb1, 0xa4, 0xe8, 0x42, 0x39, 81 0xad, 0x73, 0x07, 0xf2, 0x34, 0xdf, 0x57, 0x4f, 82 0xc0, 0x9d, 0x54, 0xbe, 0x36, 0x1b, 0x31, 0x0f, 83 0x59, 0x91, 0x52, 0x33, 0xac, 0x19, 0x9d, 0x76 84 }; 85 static const u8 pkex_resp_y_p256[32] = { 86 0x26, 0x04, 0x09, 0x45, 0x0a, 0x05, 0x20, 0xe7, 87 0xa7, 0x27, 0xc1, 0x36, 0x76, 0x85, 0xca, 0x3e, 88 0x42, 0x16, 0xf4, 0x89, 0x85, 0x34, 0x6e, 0xd5, 89 0x17, 0xde, 0xc0, 0xb8, 0xad, 0xfd, 0xb2, 0x98 90 }; 91 92 /* NIST P-384 */ 93 static const u8 pkex_init_x_p384[48] = { 94 0x95, 0x3f, 0x42, 0x9e, 0x50, 0x7f, 0xf9, 0xaa, 95 0xac, 0x1a, 0xf2, 0x85, 0x2e, 0x64, 0x91, 0x68, 96 0x64, 0xc4, 0x3c, 0xb7, 0x5c, 0xf8, 0xc9, 0x53, 97 0x6e, 0x58, 0x4c, 0x7f, 0xc4, 0x64, 0x61, 0xac, 98 0x51, 0x8a, 0x6f, 0xfe, 0xab, 0x74, 0xe6, 0x12, 99 0x81, 0xac, 0x38, 0x5d, 0x41, 0xe6, 0xb9, 0xa3 100 }; 101 static const u8 pkex_init_y_p384[48] = { 102 0x89, 0xd0, 0x97, 0x7b, 0x59, 0x4f, 0xa6, 0xd6, 103 0x7c, 0x5d, 0x93, 0x5b, 0x93, 0xc4, 0x07, 0xa9, 104 0x89, 0xee, 0xd5, 0xcd, 0x6f, 0x42, 0xf8, 0x38, 105 0xc8, 0xc6, 0x62, 0x24, 0x69, 0x0c, 0xd4, 0x48, 106 0xd8, 0x44, 0xd6, 0xc2, 0xe8, 0xcc, 0x62, 0x6b, 107 0x3c, 0x25, 0x53, 0xba, 0x4f, 0x71, 0xf8, 0xe7 108 }; 109 static const u8 pkex_resp_x_p384[48] = { 110 0xad, 0xbe, 0xd7, 0x1d, 0x3a, 0x71, 0x64, 0x98, 111 0x5f, 0xb4, 0xd6, 0x4b, 0x50, 0xd0, 0x84, 0x97, 112 0x4b, 0x7e, 0x57, 0x70, 0xd2, 0xd9, 0xf4, 0x92, 113 0x2a, 0x3f, 0xce, 0x99, 0xc5, 0x77, 0x33, 0x44, 114 0x14, 0x56, 0x92, 0xcb, 0xae, 0x46, 0x64, 0xdf, 115 0xe0, 0xbb, 0xd7, 0xb1, 0x29, 0x20, 0x72, 0xdf 116 }; 117 static const u8 pkex_resp_y_p384[48] = { 118 0x54, 0x58, 0x20, 0xad, 0x55, 0x1d, 0xca, 0xf3, 119 0x1c, 0x8a, 0xcd, 0x19, 0x40, 0xf9, 0x37, 0x83, 120 0xc7, 0xd6, 0xb3, 0x13, 0x7d, 0x53, 0x28, 0x5c, 121 0xf6, 0x2d, 0xf1, 0xdd, 0xa5, 0x8b, 0xad, 0x5d, 122 0x81, 0xab, 0xb1, 0x00, 0x39, 0xd6, 0xcc, 0x9c, 123 0xea, 0x1e, 0x84, 0x1d, 0xbf, 0xe3, 0x35, 0xf9 124 }; 125 126 /* NIST P-521 */ 127 static const u8 pkex_init_x_p521[66] = { 128 0x00, 0x16, 0x20, 0x45, 0x19, 0x50, 0x95, 0x23, 129 0x0d, 0x24, 0xbe, 0x00, 0x87, 0xdc, 0xfa, 0xf0, 130 0x58, 0x9a, 0x01, 0x60, 0x07, 0x7a, 0xca, 0x76, 131 0x01, 0xab, 0x2d, 0x5a, 0x46, 0xcd, 0x2c, 0xb5, 132 0x11, 0x9a, 0xff, 0xaa, 0x48, 0x04, 0x91, 0x38, 133 0xcf, 0x86, 0xfc, 0xa4, 0xa5, 0x0f, 0x47, 0x01, 134 0x80, 0x1b, 0x30, 0xa3, 0xae, 0xe8, 0x1c, 0x2e, 135 0xea, 0xcc, 0xf0, 0x03, 0x9f, 0x77, 0x4c, 0x8d, 136 0x97, 0x76 137 }; 138 static const u8 pkex_init_y_p521[66] = { 139 0x01, 0x4c, 0x71, 0xfd, 0x1b, 0xd5, 0x9c, 0xa6, 140 0xed, 0x39, 0xef, 0x45, 0xc5, 0x06, 0xfd, 0x66, 141 0xc0, 0xeb, 0x0f, 0xbf, 0x21, 0xa3, 0x36, 0x74, 142 0xfd, 0xaa, 0x05, 0x6e, 0x4e, 0x33, 0x95, 0x42, 143 0x1a, 0x9d, 0x3f, 0x3a, 0x1c, 0x5e, 0xa8, 0x60, 144 0xf7, 0xe5, 0x59, 0x1d, 0x07, 0xaa, 0x6f, 0x40, 145 0x0a, 0x59, 0x3c, 0x27, 0xad, 0xe0, 0x48, 0xfd, 146 0xd1, 0x83, 0x37, 0x4c, 0xdf, 0xe1, 0x86, 0x72, 147 0xfc, 0x57 148 }; 149 static const u8 pkex_resp_x_p521[66] = { 150 0x00, 0x79, 0xe4, 0x4d, 0x6b, 0x5e, 0x12, 0x0a, 151 0x18, 0x2c, 0xb3, 0x05, 0x77, 0x0f, 0xc3, 0x44, 152 0x1a, 0xcd, 0x78, 0x46, 0x14, 0xee, 0x46, 0x3f, 153 0xab, 0xc9, 0x59, 0x7c, 0x85, 0xa0, 0xc2, 0xfb, 154 0x02, 0x32, 0x99, 0xde, 0x5d, 0xe1, 0x0d, 0x48, 155 0x2d, 0x71, 0x7d, 0x8d, 0x3f, 0x61, 0x67, 0x9e, 156 0x2b, 0x8b, 0x12, 0xde, 0x10, 0x21, 0x55, 0x0a, 157 0x5b, 0x2d, 0xe8, 0x05, 0x09, 0xf6, 0x20, 0x97, 158 0x84, 0xb4 159 }; 160 static const u8 pkex_resp_y_p521[66] = { 161 0x01, 0xb9, 0x9c, 0xc6, 0x41, 0x32, 0x5b, 0xd2, 162 0x35, 0xd8, 0x8b, 0x2b, 0xe4, 0x6e, 0xcc, 0xdf, 163 0x7c, 0x38, 0xc4, 0x5b, 0xf6, 0x74, 0x71, 0x5c, 164 0x77, 0x16, 0x8a, 0x80, 0xa9, 0x84, 0xc7, 0x7b, 165 0x9d, 0xfd, 0x83, 0x6f, 0xae, 0xf8, 0x24, 0x16, 166 0x2f, 0x21, 0x25, 0x65, 0xa2, 0x1a, 0x6b, 0x2d, 167 0x30, 0x62, 0xb3, 0xcc, 0x6e, 0x59, 0x3c, 0x7f, 168 0x58, 0x91, 0x81, 0x72, 0x07, 0x8c, 0x91, 0xac, 169 0x31, 0x1e 170 }; 171 172 /* Brainpool P-256r1 */ 173 static const u8 pkex_init_x_bp_p256r1[32] = { 174 0x46, 0x98, 0x18, 0x6c, 0x27, 0xcd, 0x4b, 0x10, 175 0x7d, 0x55, 0xa3, 0xdd, 0x89, 0x1f, 0x9f, 0xca, 176 0xc7, 0x42, 0x5b, 0x8a, 0x23, 0xed, 0xf8, 0x75, 177 0xac, 0xc7, 0xe9, 0x8d, 0xc2, 0x6f, 0xec, 0xd8 178 }; 179 static const u8 pkex_init_y_bp_p256r1[32] = { 180 0x16, 0x30, 0x68, 0x32, 0x3b, 0xb0, 0x21, 0xee, 181 0xeb, 0xf7, 0xb6, 0x7c, 0xae, 0x52, 0x26, 0x42, 182 0x59, 0x28, 0x58, 0xb6, 0x14, 0x90, 0xed, 0x69, 183 0xd0, 0x67, 0xea, 0x25, 0x60, 0x0f, 0xa9, 0x6c 184 }; 185 static const u8 pkex_resp_x_bp_p256r1[32] = { 186 0x90, 0x18, 0x84, 0xc9, 0xdc, 0xcc, 0xb5, 0x2f, 187 0x4a, 0x3f, 0x4f, 0x18, 0x0a, 0x22, 0x56, 0x6a, 188 0xa9, 0xef, 0xd4, 0xe6, 0xc3, 0x53, 0xc2, 0x1a, 189 0x23, 0x54, 0xdd, 0x08, 0x7e, 0x10, 0xd8, 0xe3 190 }; 191 static const u8 pkex_resp_y_bp_p256r1[32] = { 192 0x2a, 0xfa, 0x98, 0x9b, 0xe3, 0xda, 0x30, 0xfd, 193 0x32, 0x28, 0xcb, 0x66, 0xfb, 0x40, 0x7f, 0xf2, 194 0xb2, 0x25, 0x80, 0x82, 0x44, 0x85, 0x13, 0x7e, 195 0x4b, 0xb5, 0x06, 0xc0, 0x03, 0x69, 0x23, 0x64 196 }; 197 198 /* Brainpool P-384r1 */ 199 static const u8 pkex_init_x_bp_p384r1[48] = { 200 0x0a, 0x2c, 0xeb, 0x49, 0x5e, 0xb7, 0x23, 0xbd, 201 0x20, 0x5b, 0xe0, 0x49, 0xdf, 0xcf, 0xcf, 0x19, 202 0x37, 0x36, 0xe1, 0x2f, 0x59, 0xdb, 0x07, 0x06, 203 0xb5, 0xeb, 0x2d, 0xae, 0xc2, 0xb2, 0x38, 0x62, 204 0xa6, 0x73, 0x09, 0xa0, 0x6c, 0x0a, 0xa2, 0x30, 205 0x99, 0xeb, 0xf7, 0x1e, 0x47, 0xb9, 0x5e, 0xbe 206 }; 207 static const u8 pkex_init_y_bp_p384r1[48] = { 208 0x54, 0x76, 0x61, 0x65, 0x75, 0x5a, 0x2f, 0x99, 209 0x39, 0x73, 0xca, 0x6c, 0xf9, 0xf7, 0x12, 0x86, 210 0x54, 0xd5, 0xd4, 0xad, 0x45, 0x7b, 0xbf, 0x32, 211 0xee, 0x62, 0x8b, 0x9f, 0x52, 0xe8, 0xa0, 0xc9, 212 0xb7, 0x9d, 0xd1, 0x09, 0xb4, 0x79, 0x1c, 0x3e, 213 0x1a, 0xbf, 0x21, 0x45, 0x66, 0x6b, 0x02, 0x52 214 }; 215 static const u8 pkex_resp_x_bp_p384r1[48] = { 216 0x03, 0xa2, 0x57, 0xef, 0xe8, 0x51, 0x21, 0xa0, 217 0xc8, 0x9e, 0x21, 0x02, 0xb5, 0x9a, 0x36, 0x25, 218 0x74, 0x22, 0xd1, 0xf2, 0x1b, 0xa8, 0x9a, 0x9b, 219 0x97, 0xbc, 0x5a, 0xeb, 0x26, 0x15, 0x09, 0x71, 220 0x77, 0x59, 0xec, 0x8b, 0xb7, 0xe1, 0xe8, 0xce, 221 0x65, 0xb8, 0xaf, 0xf8, 0x80, 0xae, 0x74, 0x6c 222 }; 223 static const u8 pkex_resp_y_bp_p384r1[48] = { 224 0x2f, 0xd9, 0x6a, 0xc7, 0x3e, 0xec, 0x76, 0x65, 225 0x2d, 0x38, 0x7f, 0xec, 0x63, 0x26, 0x3f, 0x04, 226 0xd8, 0x4e, 0xff, 0xe1, 0x0a, 0x51, 0x74, 0x70, 227 0xe5, 0x46, 0x63, 0x7f, 0x5c, 0xc0, 0xd1, 0x7c, 228 0xfb, 0x2f, 0xea, 0xe2, 0xd8, 0x0f, 0x84, 0xcb, 229 0xe9, 0x39, 0x5c, 0x64, 0xfe, 0xcb, 0x2f, 0xf1 230 }; 231 232 /* Brainpool P-512r1 */ 233 static const u8 pkex_init_x_bp_p512r1[64] = { 234 0x4c, 0xe9, 0xb6, 0x1c, 0xe2, 0x00, 0x3c, 0x9c, 235 0xa9, 0xc8, 0x56, 0x52, 0xaf, 0x87, 0x3e, 0x51, 236 0x9c, 0xbb, 0x15, 0x31, 0x1e, 0xc1, 0x05, 0xfc, 237 0x7c, 0x77, 0xd7, 0x37, 0x61, 0x27, 0xd0, 0x95, 238 0x98, 0xee, 0x5d, 0xa4, 0x3d, 0x09, 0xdb, 0x3d, 239 0xfa, 0x89, 0x9e, 0x7f, 0xa6, 0xa6, 0x9c, 0xff, 240 0x83, 0x5c, 0x21, 0x6c, 0x3e, 0xf2, 0xfe, 0xdc, 241 0x63, 0xe4, 0xd1, 0x0e, 0x75, 0x45, 0x69, 0x0f 242 }; 243 static const u8 pkex_init_y_bp_p512r1[64] = { 244 0x5a, 0x28, 0x01, 0xbe, 0x96, 0x82, 0x4e, 0xf6, 245 0xfa, 0xed, 0x7d, 0xfd, 0x48, 0x8b, 0x48, 0x4e, 246 0xd1, 0x97, 0x87, 0xc4, 0x05, 0x5d, 0x15, 0x2a, 247 0xf4, 0x91, 0x4b, 0x75, 0x90, 0xd9, 0x34, 0x2c, 248 0x3c, 0x12, 0xf2, 0xf5, 0x25, 0x94, 0x24, 0x34, 249 0xa7, 0x6d, 0x66, 0xbc, 0x27, 0xa4, 0xa0, 0x8d, 250 0xd5, 0xe1, 0x54, 0xa3, 0x55, 0x26, 0xd4, 0x14, 251 0x17, 0x0f, 0xc1, 0xc7, 0x3d, 0x68, 0x7f, 0x5a 252 }; 253 static const u8 pkex_resp_x_bp_p512r1[64] = { 254 0x2a, 0x60, 0x32, 0x27, 0xa1, 0xe6, 0x94, 0x72, 255 0x1c, 0x48, 0xbe, 0xc5, 0x77, 0x14, 0x30, 0x76, 256 0xe4, 0xbf, 0xf7, 0x7b, 0xc5, 0xfd, 0xdf, 0x19, 257 0x1e, 0x0f, 0xdf, 0x1c, 0x40, 0xfa, 0x34, 0x9e, 258 0x1f, 0x42, 0x24, 0xa3, 0x2c, 0xd5, 0xc7, 0xc9, 259 0x7b, 0x47, 0x78, 0x96, 0xf1, 0x37, 0x0e, 0x88, 260 0xcb, 0xa6, 0x52, 0x29, 0xd7, 0xa8, 0x38, 0x29, 261 0x8e, 0x6e, 0x23, 0x47, 0xd4, 0x4b, 0x70, 0x3e 262 }; 263 static const u8 pkex_resp_y_bp_p512r1[64] = { 264 0x2a, 0xbe, 0x59, 0xe6, 0xc4, 0xb3, 0xd8, 0x09, 265 0x66, 0x89, 0x0a, 0x2d, 0x19, 0xf0, 0x9c, 0x9f, 266 0xb4, 0xab, 0x8f, 0x50, 0x68, 0x3c, 0x74, 0x64, 267 0x4e, 0x19, 0x55, 0x81, 0x9b, 0x48, 0x5c, 0xf4, 268 0x12, 0x8d, 0xb9, 0xd8, 0x02, 0x5b, 0xe1, 0x26, 269 0x7e, 0x19, 0x5c, 0xfd, 0x70, 0xf7, 0x4b, 0xdc, 270 0xb5, 0x5d, 0xc1, 0x7a, 0xe9, 0xd1, 0x05, 0x2e, 271 0xd1, 0xfd, 0x2f, 0xce, 0x63, 0x77, 0x48, 0x2c 272 }; 273 274 275 static int dpp_hash_vector(const struct dpp_curve_params *curve, 276 size_t num_elem, const u8 *addr[], const size_t *len, 277 u8 *mac) 278 { 279 if (curve->hash_len == 32) 280 return sha256_vector(num_elem, addr, len, mac); 281 if (curve->hash_len == 48) 282 return sha384_vector(num_elem, addr, len, mac); 283 if (curve->hash_len == 64) 284 return sha512_vector(num_elem, addr, len, mac); 285 return -1; 286 } 287 288 289 static int dpp_hkdf_expand(size_t hash_len, const u8 *secret, size_t secret_len, 290 const char *label, u8 *out, size_t outlen) 291 { 292 if (hash_len == 32) 293 return hmac_sha256_kdf(secret, secret_len, NULL, 294 (const u8 *) label, os_strlen(label), 295 out, outlen); 296 if (hash_len == 48) 297 return hmac_sha384_kdf(secret, secret_len, NULL, 298 (const u8 *) label, os_strlen(label), 299 out, outlen); 300 if (hash_len == 64) 301 return hmac_sha512_kdf(secret, secret_len, NULL, 302 (const u8 *) label, os_strlen(label), 303 out, outlen); 304 return -1; 305 } 306 307 308 static int dpp_hmac_vector(size_t hash_len, const u8 *key, size_t key_len, 309 size_t num_elem, const u8 *addr[], 310 const size_t *len, u8 *mac) 311 { 312 if (hash_len == 32) 313 return hmac_sha256_vector(key, key_len, num_elem, addr, len, 314 mac); 315 if (hash_len == 48) 316 return hmac_sha384_vector(key, key_len, num_elem, addr, len, 317 mac); 318 if (hash_len == 64) 319 return hmac_sha512_vector(key, key_len, num_elem, addr, len, 320 mac); 321 return -1; 322 } 323 324 325 static int dpp_hmac(size_t hash_len, const u8 *key, size_t key_len, 326 const u8 *data, size_t data_len, u8 *mac) 327 { 328 if (hash_len == 32) 329 return hmac_sha256(key, key_len, data, data_len, mac); 330 if (hash_len == 48) 331 return hmac_sha384(key, key_len, data, data_len, mac); 332 if (hash_len == 64) 333 return hmac_sha512(key, key_len, data, data_len, mac); 334 return -1; 335 } 336 337 338 static struct wpabuf * dpp_get_pubkey_point(EVP_PKEY *pkey, int prefix) 339 { 340 int len, res; 341 EC_KEY *eckey; 342 struct wpabuf *buf; 343 unsigned char *pos; 344 345 eckey = EVP_PKEY_get1_EC_KEY(pkey); 346 if (!eckey) 347 return NULL; 348 EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED); 349 len = i2o_ECPublicKey(eckey, NULL); 350 if (len <= 0) { 351 wpa_printf(MSG_ERROR, 352 "DDP: Failed to determine public key encoding length"); 353 EC_KEY_free(eckey); 354 return NULL; 355 } 356 357 buf = wpabuf_alloc(len); 358 if (!buf) { 359 EC_KEY_free(eckey); 360 return NULL; 361 } 362 363 pos = wpabuf_put(buf, len); 364 res = i2o_ECPublicKey(eckey, &pos); 365 EC_KEY_free(eckey); 366 if (res != len) { 367 wpa_printf(MSG_ERROR, 368 "DDP: Failed to encode public key (res=%d/%d)", 369 res, len); 370 wpabuf_free(buf); 371 return NULL; 372 } 373 374 if (!prefix) { 375 /* Remove 0x04 prefix to match DPP definition */ 376 pos = wpabuf_mhead(buf); 377 os_memmove(pos, pos + 1, len - 1); 378 buf->used--; 379 } 380 381 return buf; 382 } 383 384 385 static EVP_PKEY * dpp_set_pubkey_point_group(const EC_GROUP *group, 386 const u8 *buf_x, const u8 *buf_y, 387 size_t len) 388 { 389 EC_KEY *eckey = NULL; 390 BN_CTX *ctx; 391 EC_POINT *point = NULL; 392 BIGNUM *x = NULL, *y = NULL; 393 EVP_PKEY *pkey = NULL; 394 395 ctx = BN_CTX_new(); 396 if (!ctx) { 397 wpa_printf(MSG_ERROR, "DPP: Out of memory"); 398 return NULL; 399 } 400 401 point = EC_POINT_new(group); 402 x = BN_bin2bn(buf_x, len, NULL); 403 y = BN_bin2bn(buf_y, len, NULL); 404 if (!point || !x || !y) { 405 wpa_printf(MSG_ERROR, "DPP: Out of memory"); 406 goto fail; 407 } 408 409 if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) { 410 wpa_printf(MSG_ERROR, 411 "DPP: OpenSSL: EC_POINT_set_affine_coordinates_GFp failed: %s", 412 ERR_error_string(ERR_get_error(), NULL)); 413 goto fail; 414 } 415 416 if (!EC_POINT_is_on_curve(group, point, ctx) || 417 EC_POINT_is_at_infinity(group, point)) { 418 wpa_printf(MSG_ERROR, "DPP: Invalid point"); 419 goto fail; 420 } 421 422 eckey = EC_KEY_new(); 423 if (!eckey || 424 EC_KEY_set_group(eckey, group) != 1 || 425 EC_KEY_set_public_key(eckey, point) != 1) { 426 wpa_printf(MSG_ERROR, 427 "DPP: Failed to set EC_KEY: %s", 428 ERR_error_string(ERR_get_error(), NULL)); 429 goto fail; 430 } 431 EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE); 432 433 pkey = EVP_PKEY_new(); 434 if (!pkey || EVP_PKEY_set1_EC_KEY(pkey, eckey) != 1) { 435 wpa_printf(MSG_ERROR, "DPP: Could not create EVP_PKEY"); 436 goto fail; 437 } 438 439 out: 440 BN_free(x); 441 BN_free(y); 442 EC_KEY_free(eckey); 443 EC_POINT_free(point); 444 BN_CTX_free(ctx); 445 return pkey; 446 fail: 447 EVP_PKEY_free(pkey); 448 pkey = NULL; 449 goto out; 450 } 451 452 453 static EVP_PKEY * dpp_set_pubkey_point(EVP_PKEY *group_key, 454 const u8 *buf, size_t len) 455 { 456 EC_KEY *eckey; 457 const EC_GROUP *group; 458 EVP_PKEY *pkey = NULL; 459 460 if (len & 1) 461 return NULL; 462 463 eckey = EVP_PKEY_get1_EC_KEY(group_key); 464 if (!eckey) { 465 wpa_printf(MSG_ERROR, 466 "DPP: Could not get EC_KEY from group_key"); 467 return NULL; 468 } 469 470 group = EC_KEY_get0_group(eckey); 471 if (group) 472 pkey = dpp_set_pubkey_point_group(group, buf, buf + len / 2, 473 len / 2); 474 else 475 wpa_printf(MSG_ERROR, "DPP: Could not get EC group"); 476 477 EC_KEY_free(eckey); 478 return pkey; 479 } 480 481 482 struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type, 483 size_t len) 484 { 485 struct wpabuf *msg; 486 487 msg = wpabuf_alloc(8 + len); 488 if (!msg) 489 return NULL; 490 wpabuf_put_u8(msg, WLAN_ACTION_PUBLIC); 491 wpabuf_put_u8(msg, WLAN_PA_VENDOR_SPECIFIC); 492 wpabuf_put_be24(msg, OUI_WFA); 493 wpabuf_put_u8(msg, DPP_OUI_TYPE); 494 wpabuf_put_u8(msg, 1); /* Crypto Suite */ 495 wpabuf_put_u8(msg, type); 496 return msg; 497 } 498 499 500 const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len) 501 { 502 u16 id, alen; 503 const u8 *pos = buf, *end = buf + len; 504 505 while (end - pos >= 4) { 506 id = WPA_GET_LE16(pos); 507 pos += 2; 508 alen = WPA_GET_LE16(pos); 509 pos += 2; 510 if (alen > end - pos) 511 return NULL; 512 if (id == req_id) { 513 *ret_len = alen; 514 return pos; 515 } 516 pos += alen; 517 } 518 519 return NULL; 520 } 521 522 523 int dpp_check_attrs(const u8 *buf, size_t len) 524 { 525 const u8 *pos, *end; 526 527 pos = buf; 528 end = buf + len; 529 while (end - pos >= 4) { 530 u16 id, alen; 531 532 id = WPA_GET_LE16(pos); 533 pos += 2; 534 alen = WPA_GET_LE16(pos); 535 pos += 2; 536 wpa_printf(MSG_MSGDUMP, "DPP: Attribute ID %04x len %u", 537 id, alen); 538 if (alen > end - pos) { 539 wpa_printf(MSG_DEBUG, 540 "DPP: Truncated message - not enough room for the attribute - dropped"); 541 return -1; 542 } 543 pos += alen; 544 } 545 546 if (end != pos) { 547 wpa_printf(MSG_DEBUG, 548 "DPP: Unexpected octets (%d) after the last attribute", 549 (int) (end - pos)); 550 return -1; 551 } 552 553 return 0; 554 } 555 556 557 void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info) 558 { 559 if (!info) 560 return; 561 os_free(info->uri); 562 os_free(info->info); 563 EVP_PKEY_free(info->pubkey); 564 os_free(info); 565 } 566 567 568 const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type) 569 { 570 switch (type) { 571 case DPP_BOOTSTRAP_QR_CODE: 572 return "QRCODE"; 573 case DPP_BOOTSTRAP_PKEX: 574 return "PKEX"; 575 } 576 return "??"; 577 } 578 579 580 static int dpp_uri_valid_info(const char *info) 581 { 582 while (*info) { 583 unsigned char val = *info++; 584 585 if (val < 0x20 || val > 0x7e || val == 0x3b) 586 return 0; 587 } 588 589 return 1; 590 } 591 592 593 static int dpp_clone_uri(struct dpp_bootstrap_info *bi, const char *uri) 594 { 595 bi->uri = os_strdup(uri); 596 return bi->uri ? 0 : -1; 597 } 598 599 600 int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi, 601 const char *chan_list) 602 { 603 const char *pos = chan_list; 604 int opclass, channel, freq; 605 606 while (pos && *pos && *pos != ';') { 607 opclass = atoi(pos); 608 if (opclass <= 0) 609 goto fail; 610 pos = os_strchr(pos, '/'); 611 if (!pos) 612 goto fail; 613 pos++; 614 channel = atoi(pos); 615 if (channel <= 0) 616 goto fail; 617 while (*pos >= '0' && *pos <= '9') 618 pos++; 619 freq = ieee80211_chan_to_freq(NULL, opclass, channel); 620 wpa_printf(MSG_DEBUG, 621 "DPP: URI channel-list: opclass=%d channel=%d ==> freq=%d", 622 opclass, channel, freq); 623 if (freq < 0) { 624 wpa_printf(MSG_DEBUG, 625 "DPP: Ignore unknown URI channel-list channel (opclass=%d channel=%d)", 626 opclass, channel); 627 } else if (bi->num_freq == DPP_BOOTSTRAP_MAX_FREQ) { 628 wpa_printf(MSG_DEBUG, 629 "DPP: Too many channels in URI channel-list - ignore list"); 630 bi->num_freq = 0; 631 break; 632 } else { 633 bi->freq[bi->num_freq++] = freq; 634 } 635 636 if (*pos == ';' || *pos == '\0') 637 break; 638 if (*pos != ',') 639 goto fail; 640 pos++; 641 } 642 643 return 0; 644 fail: 645 wpa_printf(MSG_DEBUG, "DPP: Invalid URI channel-list"); 646 return -1; 647 } 648 649 650 int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac) 651 { 652 if (!mac) 653 return 0; 654 655 if (hwaddr_aton2(mac, bi->mac_addr) < 0) { 656 wpa_printf(MSG_DEBUG, "DPP: Invalid URI mac"); 657 return -1; 658 } 659 660 wpa_printf(MSG_DEBUG, "DPP: URI mac: " MACSTR, MAC2STR(bi->mac_addr)); 661 662 return 0; 663 } 664 665 666 int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info) 667 { 668 const char *end; 669 670 if (!info) 671 return 0; 672 673 end = os_strchr(info, ';'); 674 if (!end) 675 end = info + os_strlen(info); 676 bi->info = os_malloc(end - info + 1); 677 if (!bi->info) 678 return -1; 679 os_memcpy(bi->info, info, end - info); 680 bi->info[end - info] = '\0'; 681 wpa_printf(MSG_DEBUG, "DPP: URI(information): %s", bi->info); 682 if (!dpp_uri_valid_info(bi->info)) { 683 wpa_printf(MSG_DEBUG, "DPP: Invalid URI information payload"); 684 return -1; 685 } 686 687 return 0; 688 } 689 690 691 static const struct dpp_curve_params * 692 dpp_get_curve_oid(const ASN1_OBJECT *poid) 693 { 694 ASN1_OBJECT *oid; 695 int i; 696 697 for (i = 0; dpp_curves[i].name; i++) { 698 oid = OBJ_txt2obj(dpp_curves[i].name, 0); 699 if (oid && OBJ_cmp(poid, oid) == 0) 700 return &dpp_curves[i]; 701 } 702 return NULL; 703 } 704 705 706 static const struct dpp_curve_params * dpp_get_curve_nid(int nid) 707 { 708 int i, tmp; 709 710 if (!nid) 711 return NULL; 712 for (i = 0; dpp_curves[i].name; i++) { 713 tmp = OBJ_txt2nid(dpp_curves[i].name); 714 if (tmp == nid) 715 return &dpp_curves[i]; 716 } 717 return NULL; 718 } 719 720 721 static int dpp_parse_uri_pk(struct dpp_bootstrap_info *bi, const char *info) 722 { 723 const char *end; 724 u8 *data; 725 size_t data_len; 726 EVP_PKEY *pkey; 727 const unsigned char *p; 728 int res; 729 X509_PUBKEY *pub = NULL; 730 ASN1_OBJECT *ppkalg; 731 const unsigned char *pk; 732 int ppklen; 733 X509_ALGOR *pa; 734 #if OPENSSL_VERSION_NUMBER < 0x10100000L 735 ASN1_OBJECT *pa_oid; 736 #else 737 const ASN1_OBJECT *pa_oid; 738 #endif 739 const void *pval; 740 int ptype; 741 const ASN1_OBJECT *poid; 742 char buf[100]; 743 744 end = os_strchr(info, ';'); 745 if (!end) 746 return -1; 747 748 data = base64_decode((const unsigned char *) info, end - info, 749 &data_len); 750 if (!data) { 751 wpa_printf(MSG_DEBUG, 752 "DPP: Invalid base64 encoding on URI public-key"); 753 return -1; 754 } 755 wpa_hexdump(MSG_DEBUG, "DPP: Base64 decoded URI public-key", 756 data, data_len); 757 758 if (sha256_vector(1, (const u8 **) &data, &data_len, 759 bi->pubkey_hash) < 0) { 760 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key"); 761 return -1; 762 } 763 wpa_hexdump(MSG_DEBUG, "DPP: Public key hash", 764 bi->pubkey_hash, SHA256_MAC_LEN); 765 766 /* DER encoded ASN.1 SubjectPublicKeyInfo 767 * 768 * SubjectPublicKeyInfo ::= SEQUENCE { 769 * algorithm AlgorithmIdentifier, 770 * subjectPublicKey BIT STRING } 771 * 772 * AlgorithmIdentifier ::= SEQUENCE { 773 * algorithm OBJECT IDENTIFIER, 774 * parameters ANY DEFINED BY algorithm OPTIONAL } 775 * 776 * subjectPublicKey = compressed format public key per ANSI X9.63 777 * algorithm = ecPublicKey (1.2.840.10045.2.1) 778 * parameters = shall be present and shall be OBJECT IDENTIFIER; e.g., 779 * prime256v1 (1.2.840.10045.3.1.7) 780 */ 781 782 p = data; 783 pkey = d2i_PUBKEY(NULL, &p, data_len); 784 os_free(data); 785 786 if (!pkey) { 787 wpa_printf(MSG_DEBUG, 788 "DPP: Could not parse URI public-key SubjectPublicKeyInfo"); 789 return -1; 790 } 791 792 if (EVP_PKEY_type(EVP_PKEY_id(pkey)) != EVP_PKEY_EC) { 793 wpa_printf(MSG_DEBUG, 794 "DPP: SubjectPublicKeyInfo does not describe an EC key"); 795 EVP_PKEY_free(pkey); 796 return -1; 797 } 798 799 res = X509_PUBKEY_set(&pub, pkey); 800 if (res != 1) { 801 wpa_printf(MSG_DEBUG, "DPP: Could not set pubkey"); 802 goto fail; 803 } 804 805 res = X509_PUBKEY_get0_param(&ppkalg, &pk, &ppklen, &pa, pub); 806 if (res != 1) { 807 wpa_printf(MSG_DEBUG, 808 "DPP: Could not extract SubjectPublicKeyInfo parameters"); 809 goto fail; 810 } 811 res = OBJ_obj2txt(buf, sizeof(buf), ppkalg, 0); 812 if (res < 0 || (size_t) res >= sizeof(buf)) { 813 wpa_printf(MSG_DEBUG, 814 "DPP: Could not extract SubjectPublicKeyInfo algorithm"); 815 goto fail; 816 } 817 wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey algorithm: %s", buf); 818 if (os_strcmp(buf, "id-ecPublicKey") != 0) { 819 wpa_printf(MSG_DEBUG, 820 "DPP: Unsupported SubjectPublicKeyInfo algorithm"); 821 goto fail; 822 } 823 824 X509_ALGOR_get0(&pa_oid, &ptype, (void *) &pval, pa); 825 if (ptype != V_ASN1_OBJECT) { 826 wpa_printf(MSG_DEBUG, 827 "DPP: SubjectPublicKeyInfo parameters did not contain an OID"); 828 goto fail; 829 } 830 poid = pval; 831 res = OBJ_obj2txt(buf, sizeof(buf), poid, 0); 832 if (res < 0 || (size_t) res >= sizeof(buf)) { 833 wpa_printf(MSG_DEBUG, 834 "DPP: Could not extract SubjectPublicKeyInfo parameters OID"); 835 goto fail; 836 } 837 wpa_printf(MSG_DEBUG, "DPP: URI subjectPublicKey parameters: %s", buf); 838 bi->curve = dpp_get_curve_oid(poid); 839 if (!bi->curve) { 840 wpa_printf(MSG_DEBUG, 841 "DPP: Unsupported SubjectPublicKeyInfo curve: %s", 842 buf); 843 goto fail; 844 } 845 846 wpa_hexdump(MSG_DEBUG, "DPP: URI subjectPublicKey", pk, ppklen); 847 848 X509_PUBKEY_free(pub); 849 bi->pubkey = pkey; 850 return 0; 851 fail: 852 X509_PUBKEY_free(pub); 853 EVP_PKEY_free(pkey); 854 return -1; 855 } 856 857 858 static struct dpp_bootstrap_info * dpp_parse_uri(const char *uri) 859 { 860 const char *pos = uri; 861 const char *end; 862 const char *chan_list = NULL, *mac = NULL, *info = NULL, *pk = NULL; 863 struct dpp_bootstrap_info *bi; 864 865 wpa_hexdump_ascii(MSG_DEBUG, "DPP: URI", uri, os_strlen(uri)); 866 867 if (os_strncmp(pos, "DPP:", 4) != 0) { 868 wpa_printf(MSG_INFO, "DPP: Not a DPP URI"); 869 return NULL; 870 } 871 pos += 4; 872 873 for (;;) { 874 end = os_strchr(pos, ';'); 875 if (!end) 876 break; 877 878 if (end == pos) { 879 /* Handle terminating ";;" and ignore unexpected ";" 880 * for parsing robustness. */ 881 pos++; 882 continue; 883 } 884 885 if (pos[0] == 'C' && pos[1] == ':' && !chan_list) 886 chan_list = pos + 2; 887 else if (pos[0] == 'M' && pos[1] == ':' && !mac) 888 mac = pos + 2; 889 else if (pos[0] == 'I' && pos[1] == ':' && !info) 890 info = pos + 2; 891 else if (pos[0] == 'K' && pos[1] == ':' && !pk) 892 pk = pos + 2; 893 else 894 wpa_hexdump_ascii(MSG_DEBUG, 895 "DPP: Ignore unrecognized URI parameter", 896 pos, end - pos); 897 pos = end + 1; 898 } 899 900 if (!pk) { 901 wpa_printf(MSG_INFO, "DPP: URI missing public-key"); 902 return NULL; 903 } 904 905 bi = os_zalloc(sizeof(*bi)); 906 if (!bi) 907 return NULL; 908 909 if (dpp_clone_uri(bi, uri) < 0 || 910 dpp_parse_uri_chan_list(bi, chan_list) < 0 || 911 dpp_parse_uri_mac(bi, mac) < 0 || 912 dpp_parse_uri_info(bi, info) < 0 || 913 dpp_parse_uri_pk(bi, pk) < 0) { 914 dpp_bootstrap_info_free(bi); 915 bi = NULL; 916 } 917 918 return bi; 919 } 920 921 922 struct dpp_bootstrap_info * dpp_parse_qr_code(const char *uri) 923 { 924 struct dpp_bootstrap_info *bi; 925 926 bi = dpp_parse_uri(uri); 927 if (bi) 928 bi->type = DPP_BOOTSTRAP_QR_CODE; 929 return bi; 930 } 931 932 933 static void dpp_debug_print_key(const char *title, EVP_PKEY *key) 934 { 935 EC_KEY *eckey; 936 BIO *out; 937 size_t rlen; 938 char *txt; 939 int res; 940 unsigned char *der = NULL; 941 int der_len; 942 943 out = BIO_new(BIO_s_mem()); 944 if (!out) 945 return; 946 947 EVP_PKEY_print_private(out, key, 0, NULL); 948 rlen = BIO_ctrl_pending(out); 949 txt = os_malloc(rlen + 1); 950 if (txt) { 951 res = BIO_read(out, txt, rlen); 952 if (res > 0) { 953 txt[res] = '\0'; 954 wpa_printf(MSG_DEBUG, "%s: %s", title, txt); 955 } 956 os_free(txt); 957 } 958 BIO_free(out); 959 960 eckey = EVP_PKEY_get1_EC_KEY(key); 961 if (!eckey) 962 return; 963 964 der_len = i2d_ECPrivateKey(eckey, &der); 965 if (der_len > 0) 966 wpa_hexdump_key(MSG_DEBUG, "DPP: ECPrivateKey", der, der_len); 967 OPENSSL_free(der); 968 if (der_len <= 0) { 969 der = NULL; 970 der_len = i2d_EC_PUBKEY(eckey, &der); 971 if (der_len > 0) 972 wpa_hexdump(MSG_DEBUG, "DPP: EC_PUBKEY", der, der_len); 973 OPENSSL_free(der); 974 } 975 976 EC_KEY_free(eckey); 977 } 978 979 980 static EVP_PKEY * dpp_gen_keypair(const struct dpp_curve_params *curve) 981 { 982 #ifdef OPENSSL_IS_BORINGSSL 983 EVP_PKEY_CTX *kctx = NULL; 984 const EC_GROUP *group; 985 EC_KEY *ec_params; 986 #else 987 EVP_PKEY_CTX *pctx, *kctx = NULL; 988 #endif 989 EVP_PKEY *params = NULL, *key = NULL; 990 int nid; 991 992 wpa_printf(MSG_DEBUG, "DPP: Generating a keypair"); 993 994 nid = OBJ_txt2nid(curve->name); 995 if (nid == NID_undef) { 996 wpa_printf(MSG_INFO, "DPP: Unsupported curve %s", curve->name); 997 return NULL; 998 } 999 #ifdef OPENSSL_IS_BORINGSSL 1000 group = EC_GROUP_new_by_curve_name(nid); 1001 ec_params = EC_KEY_new(); 1002 if (!ec_params || EC_KEY_set_group(ec_params, group) != 1) { 1003 wpa_printf(MSG_ERROR, 1004 "DPP: Failed to generate EC_KEY parameters"); 1005 goto fail; 1006 } 1007 EC_KEY_set_asn1_flag(ec_params, OPENSSL_EC_NAMED_CURVE); 1008 params = EVP_PKEY_new(); 1009 if (!params || EVP_PKEY_set1_EC_KEY(params, ec_params) != 1) { 1010 wpa_printf(MSG_ERROR, 1011 "DPP: Failed to generate EVP_PKEY parameters"); 1012 goto fail; 1013 } 1014 #else 1015 pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); 1016 if (!pctx || 1017 EVP_PKEY_paramgen_init(pctx) != 1 || 1018 EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, nid) != 1 || 1019 EVP_PKEY_CTX_set_ec_param_enc(pctx, OPENSSL_EC_NAMED_CURVE) != 1 || 1020 EVP_PKEY_paramgen(pctx, ¶ms) != 1) { 1021 wpa_printf(MSG_ERROR, 1022 "DPP: Failed to generate EVP_PKEY parameters"); 1023 EVP_PKEY_CTX_free(pctx); 1024 goto fail; 1025 } 1026 EVP_PKEY_CTX_free(pctx); 1027 #endif 1028 1029 kctx = EVP_PKEY_CTX_new(params, NULL); 1030 if (!kctx || 1031 EVP_PKEY_keygen_init(kctx) != 1 || 1032 EVP_PKEY_keygen(kctx, &key) != 1) { 1033 wpa_printf(MSG_ERROR, "DPP: Failed to generate EC key"); 1034 goto fail; 1035 } 1036 1037 if (wpa_debug_show_keys) 1038 dpp_debug_print_key("Own generated key", key); 1039 1040 EVP_PKEY_free(params); 1041 EVP_PKEY_CTX_free(kctx); 1042 return key; 1043 fail: 1044 EVP_PKEY_CTX_free(kctx); 1045 EVP_PKEY_free(params); 1046 return NULL; 1047 } 1048 1049 1050 static const struct dpp_curve_params * 1051 dpp_get_curve_name(const char *name) 1052 { 1053 int i; 1054 1055 for (i = 0; dpp_curves[i].name; i++) { 1056 if (os_strcmp(name, dpp_curves[i].name) == 0 || 1057 (dpp_curves[i].jwk_crv && 1058 os_strcmp(name, dpp_curves[i].jwk_crv) == 0)) 1059 return &dpp_curves[i]; 1060 } 1061 return NULL; 1062 } 1063 1064 1065 static const struct dpp_curve_params * 1066 dpp_get_curve_jwk_crv(const char *name) 1067 { 1068 int i; 1069 1070 for (i = 0; dpp_curves[i].name; i++) { 1071 if (dpp_curves[i].jwk_crv && 1072 os_strcmp(name, dpp_curves[i].jwk_crv) == 0) 1073 return &dpp_curves[i]; 1074 } 1075 return NULL; 1076 } 1077 1078 1079 static EVP_PKEY * dpp_set_keypair(const struct dpp_curve_params **curve, 1080 const u8 *privkey, size_t privkey_len) 1081 { 1082 EVP_PKEY *pkey; 1083 EC_KEY *eckey; 1084 const EC_GROUP *group; 1085 int nid; 1086 1087 pkey = EVP_PKEY_new(); 1088 if (!pkey) 1089 return NULL; 1090 eckey = d2i_ECPrivateKey(NULL, &privkey, privkey_len); 1091 if (!eckey) { 1092 wpa_printf(MSG_INFO, 1093 "DPP: OpenSSL: d2i_ECPrivateKey() failed: %s", 1094 ERR_error_string(ERR_get_error(), NULL)); 1095 EVP_PKEY_free(pkey); 1096 return NULL; 1097 } 1098 group = EC_KEY_get0_group(eckey); 1099 if (!group) { 1100 EC_KEY_free(eckey); 1101 EVP_PKEY_free(pkey); 1102 return NULL; 1103 } 1104 nid = EC_GROUP_get_curve_name(group); 1105 *curve = dpp_get_curve_nid(nid); 1106 if (!*curve) { 1107 wpa_printf(MSG_INFO, 1108 "DPP: Unsupported curve (nid=%d) in pre-assigned key", 1109 nid); 1110 EC_KEY_free(eckey); 1111 EVP_PKEY_free(pkey); 1112 return NULL; 1113 } 1114 1115 if (EVP_PKEY_assign_EC_KEY(pkey, eckey) != 1) { 1116 EC_KEY_free(eckey); 1117 EVP_PKEY_free(pkey); 1118 return NULL; 1119 } 1120 return pkey; 1121 } 1122 1123 1124 int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi) 1125 { 1126 unsigned char *der = NULL; 1127 int der_len; 1128 EC_KEY *eckey; 1129 int res; 1130 size_t len; 1131 1132 /* Need to get the compressed form of the public key through EC_KEY, so 1133 * cannot use the simpler i2d_PUBKEY() here. */ 1134 eckey = EVP_PKEY_get1_EC_KEY(bi->pubkey); 1135 if (!eckey) 1136 return -1; 1137 EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED); 1138 der_len = i2d_EC_PUBKEY(eckey, &der); 1139 EC_KEY_free(eckey); 1140 if (der_len <= 0) { 1141 wpa_printf(MSG_ERROR, 1142 "DDP: Failed to build DER encoded public key"); 1143 OPENSSL_free(der); 1144 return -1; 1145 } 1146 1147 len = der_len; 1148 res = sha256_vector(1, (const u8 **) &der, &len, bi->pubkey_hash); 1149 OPENSSL_free(der); 1150 if (res < 0) 1151 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key"); 1152 return res; 1153 } 1154 1155 1156 char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve, 1157 const u8 *privkey, size_t privkey_len) 1158 { 1159 unsigned char *base64 = NULL; 1160 char *pos, *end; 1161 size_t len; 1162 unsigned char *der = NULL; 1163 int der_len; 1164 EC_KEY *eckey; 1165 1166 if (!curve) { 1167 bi->curve = &dpp_curves[0]; 1168 } else { 1169 bi->curve = dpp_get_curve_name(curve); 1170 if (!bi->curve) { 1171 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", 1172 curve); 1173 return NULL; 1174 } 1175 } 1176 if (privkey) 1177 bi->pubkey = dpp_set_keypair(&bi->curve, privkey, privkey_len); 1178 else 1179 bi->pubkey = dpp_gen_keypair(bi->curve); 1180 if (!bi->pubkey) 1181 goto fail; 1182 bi->own = 1; 1183 1184 /* Need to get the compressed form of the public key through EC_KEY, so 1185 * cannot use the simpler i2d_PUBKEY() here. */ 1186 eckey = EVP_PKEY_get1_EC_KEY(bi->pubkey); 1187 if (!eckey) 1188 goto fail; 1189 EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED); 1190 der_len = i2d_EC_PUBKEY(eckey, &der); 1191 EC_KEY_free(eckey); 1192 if (der_len <= 0) { 1193 wpa_printf(MSG_ERROR, 1194 "DDP: Failed to build DER encoded public key"); 1195 goto fail; 1196 } 1197 1198 len = der_len; 1199 if (sha256_vector(1, (const u8 **) &der, &len, bi->pubkey_hash) < 0) { 1200 wpa_printf(MSG_DEBUG, "DPP: Failed to hash public key"); 1201 goto fail; 1202 } 1203 1204 base64 = base64_encode(der, der_len, &len); 1205 OPENSSL_free(der); 1206 der = NULL; 1207 if (!base64) 1208 goto fail; 1209 pos = (char *) base64; 1210 end = pos + len; 1211 for (;;) { 1212 pos = os_strchr(pos, '\n'); 1213 if (!pos) 1214 break; 1215 os_memmove(pos, pos + 1, end - pos); 1216 } 1217 return (char *) base64; 1218 fail: 1219 os_free(base64); 1220 OPENSSL_free(der); 1221 return NULL; 1222 } 1223 1224 1225 static int dpp_derive_k1(const u8 *Mx, size_t Mx_len, u8 *k1, 1226 unsigned int hash_len) 1227 { 1228 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN]; 1229 const char *info = "first intermediate key"; 1230 int res; 1231 1232 /* k1 = HKDF(<>, "first intermediate key", M.x) */ 1233 1234 /* HKDF-Extract(<>, M.x) */ 1235 os_memset(salt, 0, hash_len); 1236 if (dpp_hmac(hash_len, salt, hash_len, Mx, Mx_len, prk) < 0) 1237 return -1; 1238 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=M.x)", 1239 prk, hash_len); 1240 1241 /* HKDF-Expand(PRK, info, L) */ 1242 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k1, hash_len); 1243 os_memset(prk, 0, hash_len); 1244 if (res < 0) 1245 return -1; 1246 1247 wpa_hexdump_key(MSG_DEBUG, "DPP: k1 = HKDF-Expand(PRK, info, L)", 1248 k1, hash_len); 1249 return 0; 1250 } 1251 1252 1253 static int dpp_derive_k2(const u8 *Nx, size_t Nx_len, u8 *k2, 1254 unsigned int hash_len) 1255 { 1256 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN]; 1257 const char *info = "second intermediate key"; 1258 int res; 1259 1260 /* k2 = HKDF(<>, "second intermediate key", N.x) */ 1261 1262 /* HKDF-Extract(<>, N.x) */ 1263 os_memset(salt, 0, hash_len); 1264 res = dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk); 1265 if (res < 0) 1266 return -1; 1267 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)", 1268 prk, hash_len); 1269 1270 /* HKDF-Expand(PRK, info, L) */ 1271 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, k2, hash_len); 1272 os_memset(prk, 0, hash_len); 1273 if (res < 0) 1274 return -1; 1275 1276 wpa_hexdump_key(MSG_DEBUG, "DPP: k2 = HKDF-Expand(PRK, info, L)", 1277 k2, hash_len); 1278 return 0; 1279 } 1280 1281 1282 static int dpp_derive_ke(struct dpp_authentication *auth, u8 *ke, 1283 unsigned int hash_len) 1284 { 1285 size_t nonce_len; 1286 u8 nonces[2 * DPP_MAX_NONCE_LEN]; 1287 const char *info_ke = "DPP Key"; 1288 u8 prk[DPP_MAX_HASH_LEN]; 1289 int res; 1290 const u8 *addr[3]; 1291 size_t len[3]; 1292 size_t num_elem = 0; 1293 1294 /* ke = HKDF(I-nonce | R-nonce, "DPP Key", M.x | N.x [| L.x]) */ 1295 1296 /* HKDF-Extract(I-nonce | R-nonce, M.x | N.x [| L.x]) */ 1297 nonce_len = auth->curve->nonce_len; 1298 os_memcpy(nonces, auth->i_nonce, nonce_len); 1299 os_memcpy(&nonces[nonce_len], auth->r_nonce, nonce_len); 1300 addr[num_elem] = auth->Mx; 1301 len[num_elem] = auth->secret_len; 1302 num_elem++; 1303 addr[num_elem] = auth->Nx; 1304 len[num_elem] = auth->secret_len; 1305 num_elem++; 1306 if (auth->peer_bi && auth->own_bi) { 1307 addr[num_elem] = auth->Lx; 1308 len[num_elem] = auth->secret_len; 1309 num_elem++; 1310 } 1311 res = dpp_hmac_vector(hash_len, nonces, 2 * nonce_len, 1312 num_elem, addr, len, prk); 1313 if (res < 0) 1314 return -1; 1315 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)", 1316 prk, hash_len); 1317 1318 /* HKDF-Expand(PRK, info, L) */ 1319 res = dpp_hkdf_expand(hash_len, prk, hash_len, info_ke, ke, hash_len); 1320 os_memset(prk, 0, hash_len); 1321 if (res < 0) 1322 return -1; 1323 1324 wpa_hexdump_key(MSG_DEBUG, "DPP: ke = HKDF-Expand(PRK, info, L)", 1325 ke, hash_len); 1326 return 0; 1327 } 1328 1329 1330 struct dpp_authentication * dpp_auth_init(void *msg_ctx, 1331 struct dpp_bootstrap_info *peer_bi, 1332 struct dpp_bootstrap_info *own_bi, 1333 int configurator) 1334 { 1335 struct dpp_authentication *auth; 1336 size_t nonce_len; 1337 EVP_PKEY_CTX *ctx = NULL; 1338 size_t secret_len; 1339 struct wpabuf *msg, *pi = NULL; 1340 u8 clear[4 + DPP_MAX_NONCE_LEN + 4 + 1]; 1341 u8 wrapped_data[4 + DPP_MAX_NONCE_LEN + 4 + 1 + AES_BLOCK_SIZE]; 1342 u8 *pos; 1343 const u8 *addr[2]; 1344 size_t len[2], siv_len, attr_len; 1345 u8 *attr_start, *attr_end; 1346 1347 auth = os_zalloc(sizeof(*auth)); 1348 if (!auth) 1349 return NULL; 1350 auth->msg_ctx = msg_ctx; 1351 auth->initiator = 1; 1352 auth->configurator = configurator; 1353 auth->peer_bi = peer_bi; 1354 auth->own_bi = own_bi; 1355 auth->curve = peer_bi->curve; 1356 1357 nonce_len = auth->curve->nonce_len; 1358 if (random_get_bytes(auth->i_nonce, nonce_len)) { 1359 wpa_printf(MSG_ERROR, "DPP: Failed to generate I-nonce"); 1360 goto fail; 1361 } 1362 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", auth->i_nonce, nonce_len); 1363 1364 auth->own_protocol_key = dpp_gen_keypair(auth->curve); 1365 if (!auth->own_protocol_key) 1366 goto fail; 1367 1368 pi = dpp_get_pubkey_point(auth->own_protocol_key, 0); 1369 if (!pi) 1370 goto fail; 1371 1372 /* ECDH: M = pI * BR */ 1373 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL); 1374 if (!ctx || 1375 EVP_PKEY_derive_init(ctx) != 1 || 1376 EVP_PKEY_derive_set_peer(ctx, auth->peer_bi->pubkey) != 1 || 1377 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 || 1378 secret_len > DPP_MAX_SHARED_SECRET_LEN || 1379 EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) { 1380 wpa_printf(MSG_ERROR, 1381 "DPP: Failed to derive ECDH shared secret: %s", 1382 ERR_error_string(ERR_get_error(), NULL)); 1383 goto fail; 1384 } 1385 auth->secret_len = secret_len; 1386 EVP_PKEY_CTX_free(ctx); 1387 ctx = NULL; 1388 1389 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)", 1390 auth->Mx, auth->secret_len); 1391 1392 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1, 1393 auth->curve->hash_len) < 0) 1394 goto fail; 1395 1396 /* Build DPP Authentication Request frame attributes */ 1397 attr_len = 2 * (4 + SHA256_MAC_LEN) + 4 + wpabuf_len(pi) + 1398 4 + sizeof(wrapped_data); 1399 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_REQ, attr_len); 1400 if (!msg) 1401 goto fail; 1402 auth->req_msg = msg; 1403 1404 attr_start = wpabuf_put(msg, 0); 1405 1406 /* Responder Bootstrapping Key Hash */ 1407 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH); 1408 wpabuf_put_le16(msg, SHA256_MAC_LEN); 1409 wpabuf_put_data(msg, auth->peer_bi->pubkey_hash, SHA256_MAC_LEN); 1410 1411 /* Initiator Bootstrapping Key Hash */ 1412 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH); 1413 wpabuf_put_le16(msg, SHA256_MAC_LEN); 1414 if (auth->own_bi) 1415 wpabuf_put_data(msg, auth->own_bi->pubkey_hash, SHA256_MAC_LEN); 1416 else 1417 os_memset(wpabuf_put(msg, SHA256_MAC_LEN), 0, SHA256_MAC_LEN); 1418 1419 /* Initiator Protocol Key */ 1420 wpabuf_put_le16(msg, DPP_ATTR_I_PROTOCOL_KEY); 1421 wpabuf_put_le16(msg, wpabuf_len(pi)); 1422 wpabuf_put_buf(msg, pi); 1423 wpabuf_free(pi); 1424 pi = NULL; 1425 1426 /* Wrapped data ({I-nonce, I-capabilities}k1) */ 1427 pos = clear; 1428 /* I-nonce */ 1429 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE); 1430 pos += 2; 1431 WPA_PUT_LE16(pos, nonce_len); 1432 pos += 2; 1433 os_memcpy(pos, auth->i_nonce, nonce_len); 1434 pos += nonce_len; 1435 /* I-capabilities */ 1436 WPA_PUT_LE16(pos, DPP_ATTR_I_CAPABILITIES); 1437 pos += 2; 1438 WPA_PUT_LE16(pos, 1); 1439 pos += 2; 1440 auth->i_capab = configurator ? DPP_CAPAB_CONFIGURATOR : 1441 DPP_CAPAB_ENROLLEE; 1442 *pos++ = auth->i_capab; 1443 1444 attr_end = wpabuf_put(msg, 0); 1445 1446 /* OUI, OUI type, Crypto Suite, DPP frame type */ 1447 addr[0] = wpabuf_head_u8(msg) + 2; 1448 len[0] = 3 + 1 + 1 + 1; 1449 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 1450 1451 /* Attributes before Wrapped Data */ 1452 addr[1] = attr_start; 1453 len[1] = attr_end - attr_start; 1454 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 1455 1456 siv_len = pos - clear; 1457 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len); 1458 if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len, 1459 2, addr, len, wrapped_data) < 0) 1460 goto fail; 1461 siv_len += AES_BLOCK_SIZE; 1462 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 1463 wrapped_data, siv_len); 1464 1465 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 1466 wpabuf_put_le16(msg, siv_len); 1467 wpabuf_put_data(msg, wrapped_data, siv_len); 1468 1469 wpa_hexdump_buf(MSG_DEBUG, 1470 "DPP: Authentication Request frame attributes", msg); 1471 1472 return auth; 1473 fail: 1474 wpabuf_free(pi); 1475 EVP_PKEY_CTX_free(ctx); 1476 dpp_auth_deinit(auth); 1477 return NULL; 1478 } 1479 1480 1481 struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth, 1482 const char *json) 1483 { 1484 size_t nonce_len; 1485 size_t json_len, clear_len; 1486 struct wpabuf *clear = NULL, *msg = NULL; 1487 u8 *wrapped; 1488 1489 wpa_printf(MSG_DEBUG, "DPP: Build configuration request"); 1490 1491 nonce_len = auth->curve->nonce_len; 1492 if (random_get_bytes(auth->e_nonce, nonce_len)) { 1493 wpa_printf(MSG_ERROR, "DPP: Failed to generate E-nonce"); 1494 goto fail; 1495 } 1496 wpa_hexdump(MSG_DEBUG, "DPP: E-nonce", auth->e_nonce, nonce_len); 1497 json_len = os_strlen(json); 1498 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configAttr JSON", json, json_len); 1499 1500 /* { E-nonce, configAttrib }ke */ 1501 clear_len = 4 + nonce_len + 4 + json_len; 1502 clear = wpabuf_alloc(clear_len); 1503 msg = wpabuf_alloc(4 + clear_len + AES_BLOCK_SIZE); 1504 if (!clear || !msg) 1505 goto fail; 1506 1507 /* E-nonce */ 1508 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE); 1509 wpabuf_put_le16(clear, nonce_len); 1510 wpabuf_put_data(clear, auth->e_nonce, nonce_len); 1511 1512 /* configAttrib */ 1513 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_ATTR_OBJ); 1514 wpabuf_put_le16(clear, json_len); 1515 wpabuf_put_data(clear, json, json_len); 1516 1517 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 1518 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 1519 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 1520 1521 /* No AES-SIV AD */ 1522 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 1523 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len, 1524 wpabuf_head(clear), wpabuf_len(clear), 1525 0, NULL, NULL, wrapped) < 0) 1526 goto fail; 1527 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 1528 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE); 1529 1530 wpa_hexdump_buf(MSG_DEBUG, 1531 "DPP: Configuration Request frame attributes", msg); 1532 wpabuf_free(clear); 1533 return msg; 1534 1535 fail: 1536 wpabuf_free(clear); 1537 wpabuf_free(msg); 1538 return NULL; 1539 } 1540 1541 1542 static void dpp_auth_success(struct dpp_authentication *auth) 1543 { 1544 wpa_printf(MSG_DEBUG, 1545 "DPP: Authentication success - clear temporary keys"); 1546 os_memset(auth->Mx, 0, sizeof(auth->Mx)); 1547 os_memset(auth->Nx, 0, sizeof(auth->Nx)); 1548 os_memset(auth->Lx, 0, sizeof(auth->Lx)); 1549 os_memset(auth->k1, 0, sizeof(auth->k1)); 1550 os_memset(auth->k2, 0, sizeof(auth->k2)); 1551 1552 auth->auth_success = 1; 1553 } 1554 1555 1556 static int dpp_gen_r_auth(struct dpp_authentication *auth, u8 *r_auth) 1557 { 1558 struct wpabuf *pix, *prx, *bix, *brx; 1559 const u8 *addr[7]; 1560 size_t len[7]; 1561 size_t i, num_elem = 0; 1562 size_t nonce_len; 1563 u8 zero = 0; 1564 int res = -1; 1565 1566 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */ 1567 nonce_len = auth->curve->nonce_len; 1568 1569 if (auth->initiator) { 1570 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0); 1571 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0); 1572 if (auth->own_bi) 1573 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0); 1574 else 1575 bix = NULL; 1576 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0); 1577 } else { 1578 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0); 1579 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0); 1580 if (auth->peer_bi) 1581 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0); 1582 else 1583 bix = NULL; 1584 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0); 1585 } 1586 if (!pix || !prx || !brx) 1587 goto fail; 1588 1589 addr[num_elem] = auth->i_nonce; 1590 len[num_elem] = nonce_len; 1591 num_elem++; 1592 1593 addr[num_elem] = auth->r_nonce; 1594 len[num_elem] = nonce_len; 1595 num_elem++; 1596 1597 addr[num_elem] = wpabuf_head(pix); 1598 len[num_elem] = wpabuf_len(pix) / 2; 1599 num_elem++; 1600 1601 addr[num_elem] = wpabuf_head(prx); 1602 len[num_elem] = wpabuf_len(prx) / 2; 1603 num_elem++; 1604 1605 if (bix) { 1606 addr[num_elem] = wpabuf_head(bix); 1607 len[num_elem] = wpabuf_len(bix) / 2; 1608 num_elem++; 1609 } 1610 1611 addr[num_elem] = wpabuf_head(brx); 1612 len[num_elem] = wpabuf_len(brx) / 2; 1613 num_elem++; 1614 1615 addr[num_elem] = &zero; 1616 len[num_elem] = 1; 1617 num_elem++; 1618 1619 wpa_printf(MSG_DEBUG, "DPP: R-auth hash components"); 1620 for (i = 0; i < num_elem; i++) 1621 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]); 1622 res = dpp_hash_vector(auth->curve, num_elem, addr, len, r_auth); 1623 if (res == 0) 1624 wpa_hexdump(MSG_DEBUG, "DPP: R-auth", r_auth, 1625 auth->curve->hash_len); 1626 fail: 1627 wpabuf_free(pix); 1628 wpabuf_free(prx); 1629 wpabuf_free(bix); 1630 wpabuf_free(brx); 1631 return res; 1632 } 1633 1634 1635 static int dpp_gen_i_auth(struct dpp_authentication *auth, u8 *i_auth) 1636 { 1637 struct wpabuf *pix = NULL, *prx = NULL, *bix = NULL, *brx = NULL; 1638 const u8 *addr[7]; 1639 size_t len[7]; 1640 size_t i, num_elem = 0; 1641 size_t nonce_len; 1642 u8 one = 1; 1643 int res = -1; 1644 1645 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */ 1646 nonce_len = auth->curve->nonce_len; 1647 1648 if (auth->initiator) { 1649 pix = dpp_get_pubkey_point(auth->own_protocol_key, 0); 1650 prx = dpp_get_pubkey_point(auth->peer_protocol_key, 0); 1651 if (auth->own_bi) 1652 bix = dpp_get_pubkey_point(auth->own_bi->pubkey, 0); 1653 else 1654 bix = NULL; 1655 if (!auth->peer_bi) 1656 goto fail; 1657 brx = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0); 1658 } else { 1659 pix = dpp_get_pubkey_point(auth->peer_protocol_key, 0); 1660 prx = dpp_get_pubkey_point(auth->own_protocol_key, 0); 1661 if (auth->peer_bi) 1662 bix = dpp_get_pubkey_point(auth->peer_bi->pubkey, 0); 1663 else 1664 bix = NULL; 1665 if (!auth->own_bi) 1666 goto fail; 1667 brx = dpp_get_pubkey_point(auth->own_bi->pubkey, 0); 1668 } 1669 if (!pix || !prx || !brx) 1670 goto fail; 1671 1672 addr[num_elem] = auth->r_nonce; 1673 len[num_elem] = nonce_len; 1674 num_elem++; 1675 1676 addr[num_elem] = auth->i_nonce; 1677 len[num_elem] = nonce_len; 1678 num_elem++; 1679 1680 addr[num_elem] = wpabuf_head(prx); 1681 len[num_elem] = wpabuf_len(prx) / 2; 1682 num_elem++; 1683 1684 addr[num_elem] = wpabuf_head(pix); 1685 len[num_elem] = wpabuf_len(pix) / 2; 1686 num_elem++; 1687 1688 addr[num_elem] = wpabuf_head(brx); 1689 len[num_elem] = wpabuf_len(brx) / 2; 1690 num_elem++; 1691 1692 if (bix) { 1693 addr[num_elem] = wpabuf_head(bix); 1694 len[num_elem] = wpabuf_len(bix) / 2; 1695 num_elem++; 1696 } 1697 1698 addr[num_elem] = &one; 1699 len[num_elem] = 1; 1700 num_elem++; 1701 1702 wpa_printf(MSG_DEBUG, "DPP: I-auth hash components"); 1703 for (i = 0; i < num_elem; i++) 1704 wpa_hexdump(MSG_DEBUG, "DPP: hash component", addr[i], len[i]); 1705 res = dpp_hash_vector(auth->curve, num_elem, addr, len, i_auth); 1706 if (res == 0) 1707 wpa_hexdump(MSG_DEBUG, "DPP: I-auth", i_auth, 1708 auth->curve->hash_len); 1709 fail: 1710 wpabuf_free(pix); 1711 wpabuf_free(prx); 1712 wpabuf_free(bix); 1713 wpabuf_free(brx); 1714 return res; 1715 } 1716 1717 1718 static int dpp_auth_derive_l_responder(struct dpp_authentication *auth) 1719 { 1720 const EC_GROUP *group; 1721 EC_POINT *l = NULL; 1722 EC_KEY *BI = NULL, *bR = NULL, *pR = NULL; 1723 const EC_POINT *BI_point; 1724 BN_CTX *bnctx; 1725 BIGNUM *lx, *sum, *q; 1726 const BIGNUM *bR_bn, *pR_bn; 1727 int ret = -1; 1728 int num_bytes, offset; 1729 1730 /* L = ((bR + pR) modulo q) * BI */ 1731 1732 bnctx = BN_CTX_new(); 1733 sum = BN_new(); 1734 q = BN_new(); 1735 lx = BN_new(); 1736 if (!bnctx || !sum || !q || !lx) 1737 goto fail; 1738 BI = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey); 1739 if (!BI) 1740 goto fail; 1741 BI_point = EC_KEY_get0_public_key(BI); 1742 group = EC_KEY_get0_group(BI); 1743 if (!group) 1744 goto fail; 1745 1746 bR = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey); 1747 pR = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key); 1748 if (!bR || !pR) 1749 goto fail; 1750 bR_bn = EC_KEY_get0_private_key(bR); 1751 pR_bn = EC_KEY_get0_private_key(pR); 1752 if (!bR_bn || !pR_bn) 1753 goto fail; 1754 if (EC_GROUP_get_order(group, q, bnctx) != 1 || 1755 BN_mod_add(sum, bR_bn, pR_bn, q, bnctx) != 1) 1756 goto fail; 1757 l = EC_POINT_new(group); 1758 if (!l || 1759 EC_POINT_mul(group, l, NULL, BI_point, sum, bnctx) != 1 || 1760 EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL, 1761 bnctx) != 1) { 1762 wpa_printf(MSG_ERROR, 1763 "OpenSSL: failed: %s", 1764 ERR_error_string(ERR_get_error(), NULL)); 1765 goto fail; 1766 } 1767 1768 num_bytes = BN_num_bytes(lx); 1769 if ((size_t) num_bytes > auth->secret_len) 1770 goto fail; 1771 if (auth->secret_len > (size_t) num_bytes) 1772 offset = auth->secret_len - num_bytes; 1773 else 1774 offset = 0; 1775 1776 os_memset(auth->Lx, 0, offset); 1777 BN_bn2bin(lx, auth->Lx + offset); 1778 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len); 1779 ret = 0; 1780 fail: 1781 EC_POINT_clear_free(l); 1782 EC_KEY_free(BI); 1783 EC_KEY_free(bR); 1784 EC_KEY_free(pR); 1785 BN_clear_free(lx); 1786 BN_clear_free(sum); 1787 BN_free(q); 1788 BN_CTX_free(bnctx); 1789 return ret; 1790 } 1791 1792 1793 static int dpp_auth_derive_l_initiator(struct dpp_authentication *auth) 1794 { 1795 const EC_GROUP *group; 1796 EC_POINT *l = NULL, *sum = NULL; 1797 EC_KEY *bI = NULL, *BR = NULL, *PR = NULL; 1798 const EC_POINT *BR_point, *PR_point; 1799 BN_CTX *bnctx; 1800 BIGNUM *lx; 1801 const BIGNUM *bI_bn; 1802 int ret = -1; 1803 int num_bytes, offset; 1804 1805 /* L = bI * (BR + PR) */ 1806 1807 bnctx = BN_CTX_new(); 1808 lx = BN_new(); 1809 if (!bnctx || !lx) 1810 goto fail; 1811 BR = EVP_PKEY_get1_EC_KEY(auth->peer_bi->pubkey); 1812 PR = EVP_PKEY_get1_EC_KEY(auth->peer_protocol_key); 1813 if (!BR || !PR) 1814 goto fail; 1815 BR_point = EC_KEY_get0_public_key(BR); 1816 PR_point = EC_KEY_get0_public_key(PR); 1817 1818 bI = EVP_PKEY_get1_EC_KEY(auth->own_bi->pubkey); 1819 if (!bI) 1820 goto fail; 1821 group = EC_KEY_get0_group(bI); 1822 bI_bn = EC_KEY_get0_private_key(bI); 1823 if (!group || !bI_bn) 1824 goto fail; 1825 sum = EC_POINT_new(group); 1826 l = EC_POINT_new(group); 1827 if (!sum || !l || 1828 EC_POINT_add(group, sum, BR_point, PR_point, bnctx) != 1 || 1829 EC_POINT_mul(group, l, NULL, sum, bI_bn, bnctx) != 1 || 1830 EC_POINT_get_affine_coordinates_GFp(group, l, lx, NULL, 1831 bnctx) != 1) { 1832 wpa_printf(MSG_ERROR, 1833 "OpenSSL: failed: %s", 1834 ERR_error_string(ERR_get_error(), NULL)); 1835 goto fail; 1836 } 1837 1838 num_bytes = BN_num_bytes(lx); 1839 if ((size_t) num_bytes > auth->secret_len) 1840 goto fail; 1841 if (auth->secret_len > (size_t) num_bytes) 1842 offset = auth->secret_len - num_bytes; 1843 else 1844 offset = 0; 1845 1846 os_memset(auth->Lx, 0, offset); 1847 BN_bn2bin(lx, auth->Lx + offset); 1848 wpa_hexdump_key(MSG_DEBUG, "DPP: L.x", auth->Lx, auth->secret_len); 1849 ret = 0; 1850 fail: 1851 EC_POINT_clear_free(l); 1852 EC_KEY_free(bI); 1853 EC_KEY_free(BR); 1854 EC_KEY_free(PR); 1855 BN_clear_free(lx); 1856 BN_CTX_free(bnctx); 1857 return ret; 1858 } 1859 1860 1861 static int dpp_auth_build_resp(struct dpp_authentication *auth) 1862 { 1863 size_t nonce_len; 1864 EVP_PKEY_CTX *ctx = NULL; 1865 size_t secret_len; 1866 struct wpabuf *msg, *pr = NULL; 1867 u8 r_auth[4 + DPP_MAX_HASH_LEN]; 1868 u8 wrapped_r_auth[4 + DPP_MAX_HASH_LEN + AES_BLOCK_SIZE]; 1869 #define DPP_AUTH_RESP_CLEAR_LEN 2 * (4 + DPP_MAX_NONCE_LEN) + 4 + 1 + \ 1870 4 + sizeof(wrapped_r_auth) 1871 size_t wrapped_r_auth_len; 1872 u8 clear[DPP_AUTH_RESP_CLEAR_LEN]; 1873 u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN + AES_BLOCK_SIZE]; 1874 u8 *pos; 1875 const u8 *addr[2]; 1876 size_t len[2], siv_len, attr_len; 1877 u8 *attr_start, *attr_end; 1878 1879 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response"); 1880 1881 nonce_len = auth->curve->nonce_len; 1882 if (random_get_bytes(auth->r_nonce, nonce_len)) { 1883 wpa_printf(MSG_ERROR, "DPP: Failed to generate R-nonce"); 1884 goto fail; 1885 } 1886 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", auth->r_nonce, nonce_len); 1887 1888 auth->own_protocol_key = dpp_gen_keypair(auth->curve); 1889 if (!auth->own_protocol_key) 1890 goto fail; 1891 1892 pr = dpp_get_pubkey_point(auth->own_protocol_key, 0); 1893 if (!pr) 1894 goto fail; 1895 1896 /* ECDH: N = pR * PI */ 1897 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL); 1898 if (!ctx || 1899 EVP_PKEY_derive_init(ctx) != 1 || 1900 EVP_PKEY_derive_set_peer(ctx, auth->peer_protocol_key) != 1 || 1901 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 || 1902 secret_len > DPP_MAX_SHARED_SECRET_LEN || 1903 EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) { 1904 wpa_printf(MSG_ERROR, 1905 "DPP: Failed to derive ECDH shared secret: %s", 1906 ERR_error_string(ERR_get_error(), NULL)); 1907 goto fail; 1908 } 1909 EVP_PKEY_CTX_free(ctx); 1910 ctx = NULL; 1911 1912 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)", 1913 auth->Nx, auth->secret_len); 1914 1915 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2, 1916 auth->curve->hash_len) < 0) 1917 goto fail; 1918 1919 if (auth->own_bi && auth->peer_bi) { 1920 /* Mutual authentication */ 1921 if (dpp_auth_derive_l_responder(auth) < 0) 1922 goto fail; 1923 } 1924 1925 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0) 1926 goto fail; 1927 1928 /* R-auth = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */ 1929 WPA_PUT_LE16(r_auth, DPP_ATTR_R_AUTH_TAG); 1930 WPA_PUT_LE16(&r_auth[2], auth->curve->hash_len); 1931 if (dpp_gen_r_auth(auth, r_auth + 4) < 0 || 1932 aes_siv_encrypt(auth->ke, auth->curve->hash_len, 1933 r_auth, 4 + auth->curve->hash_len, 1934 0, NULL, NULL, wrapped_r_auth) < 0) 1935 goto fail; 1936 wrapped_r_auth_len = 4 + auth->curve->hash_len + AES_BLOCK_SIZE; 1937 wpa_hexdump(MSG_DEBUG, "DPP: {R-auth}ke", 1938 wrapped_r_auth, wrapped_r_auth_len); 1939 1940 /* Build DPP Authentication Response frame attributes */ 1941 attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) + 1942 4 + wpabuf_len(pr) + 4 + sizeof(wrapped_data); 1943 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len); 1944 if (!msg) 1945 goto fail; 1946 wpabuf_free(auth->resp_msg); 1947 auth->resp_msg = msg; 1948 1949 attr_start = wpabuf_put(msg, 0); 1950 1951 /* DPP Status */ 1952 wpabuf_put_le16(msg, DPP_ATTR_STATUS); 1953 wpabuf_put_le16(msg, 1); 1954 wpabuf_put_u8(msg, DPP_STATUS_OK); 1955 1956 /* Responder Bootstrapping Key Hash */ 1957 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH); 1958 wpabuf_put_le16(msg, SHA256_MAC_LEN); 1959 wpabuf_put_data(msg, auth->own_bi->pubkey_hash, SHA256_MAC_LEN); 1960 1961 if (auth->peer_bi) { 1962 /* Mutual authentication */ 1963 /* Initiator Bootstrapping Key Hash */ 1964 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH); 1965 wpabuf_put_le16(msg, SHA256_MAC_LEN); 1966 wpabuf_put_data(msg, auth->peer_bi->pubkey_hash, 1967 SHA256_MAC_LEN); 1968 } 1969 1970 /* Responder Protocol Key */ 1971 wpabuf_put_le16(msg, DPP_ATTR_R_PROTOCOL_KEY); 1972 wpabuf_put_le16(msg, wpabuf_len(pr)); 1973 wpabuf_put_buf(msg, pr); 1974 wpabuf_free(pr); 1975 pr = NULL; 1976 1977 attr_end = wpabuf_put(msg, 0); 1978 1979 /* Wrapped data ({R-nonce, I-nonce, R-capabilities, {R-auth}ke}k2) */ 1980 pos = clear; 1981 /* R-nonce */ 1982 WPA_PUT_LE16(pos, DPP_ATTR_R_NONCE); 1983 pos += 2; 1984 WPA_PUT_LE16(pos, nonce_len); 1985 pos += 2; 1986 os_memcpy(pos, auth->r_nonce, nonce_len); 1987 pos += nonce_len; 1988 /* I-nonce */ 1989 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE); 1990 pos += 2; 1991 WPA_PUT_LE16(pos, nonce_len); 1992 pos += 2; 1993 os_memcpy(pos, auth->i_nonce, nonce_len); 1994 pos += nonce_len; 1995 /* R-capabilities */ 1996 WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES); 1997 pos += 2; 1998 WPA_PUT_LE16(pos, 1); 1999 pos += 2; 2000 auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR : 2001 DPP_CAPAB_ENROLLEE; 2002 *pos++ = auth->r_capab; 2003 /* {R-auth}ke */ 2004 WPA_PUT_LE16(pos, DPP_ATTR_WRAPPED_DATA); 2005 pos += 2; 2006 WPA_PUT_LE16(pos, wrapped_r_auth_len); 2007 pos += 2; 2008 os_memcpy(pos, wrapped_r_auth, wrapped_r_auth_len); 2009 pos += wrapped_r_auth_len; 2010 2011 /* OUI, OUI type, Crypto Suite, DPP frame type */ 2012 addr[0] = wpabuf_head_u8(msg) + 2; 2013 len[0] = 3 + 1 + 1 + 1; 2014 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 2015 2016 /* Attributes before Wrapped Data */ 2017 addr[1] = attr_start; 2018 len[1] = attr_end - attr_start; 2019 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 2020 2021 siv_len = pos - clear; 2022 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len); 2023 if (aes_siv_encrypt(auth->k2, auth->curve->hash_len, clear, siv_len, 2024 2, addr, len, wrapped_data) < 0) 2025 goto fail; 2026 siv_len += AES_BLOCK_SIZE; 2027 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 2028 wrapped_data, siv_len); 2029 2030 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 2031 wpabuf_put_le16(msg, siv_len); 2032 wpabuf_put_data(msg, wrapped_data, siv_len); 2033 2034 wpa_hexdump_buf(MSG_DEBUG, 2035 "DPP: Authentication Response frame attributes", msg); 2036 2037 return 0; 2038 2039 fail: 2040 wpabuf_free(pr); 2041 return -1; 2042 } 2043 2044 2045 static int dpp_auth_build_resp_status(struct dpp_authentication *auth, 2046 enum dpp_status_error status) 2047 { 2048 size_t nonce_len; 2049 struct wpabuf *msg; 2050 #define DPP_AUTH_RESP_CLEAR_LEN2 4 + DPP_MAX_NONCE_LEN + 4 + 1 2051 u8 clear[DPP_AUTH_RESP_CLEAR_LEN2]; 2052 u8 wrapped_data[DPP_AUTH_RESP_CLEAR_LEN2 + AES_BLOCK_SIZE]; 2053 u8 *pos; 2054 const u8 *addr[2]; 2055 size_t len[2], siv_len, attr_len; 2056 u8 *attr_start, *attr_end; 2057 2058 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Response"); 2059 2060 /* Build DPP Authentication Response frame attributes */ 2061 attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) + 4 + sizeof(wrapped_data); 2062 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_RESP, attr_len); 2063 if (!msg) 2064 goto fail; 2065 wpabuf_free(auth->resp_msg); 2066 auth->resp_msg = msg; 2067 2068 attr_start = wpabuf_put(msg, 0); 2069 2070 /* DPP Status */ 2071 wpabuf_put_le16(msg, DPP_ATTR_STATUS); 2072 wpabuf_put_le16(msg, 1); 2073 wpabuf_put_u8(msg, status); 2074 2075 /* Responder Bootstrapping Key Hash */ 2076 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH); 2077 wpabuf_put_le16(msg, SHA256_MAC_LEN); 2078 wpabuf_put_data(msg, auth->own_bi->pubkey_hash, SHA256_MAC_LEN); 2079 2080 if (auth->peer_bi) { 2081 /* Mutual authentication */ 2082 /* Initiator Bootstrapping Key Hash */ 2083 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH); 2084 wpabuf_put_le16(msg, SHA256_MAC_LEN); 2085 wpabuf_put_data(msg, auth->peer_bi->pubkey_hash, 2086 SHA256_MAC_LEN); 2087 } 2088 2089 attr_end = wpabuf_put(msg, 0); 2090 2091 /* Wrapped data ({I-nonce, R-capabilities}k1) */ 2092 pos = clear; 2093 /* I-nonce */ 2094 nonce_len = auth->curve->nonce_len; 2095 WPA_PUT_LE16(pos, DPP_ATTR_I_NONCE); 2096 pos += 2; 2097 WPA_PUT_LE16(pos, nonce_len); 2098 pos += 2; 2099 os_memcpy(pos, auth->i_nonce, nonce_len); 2100 pos += nonce_len; 2101 /* R-capabilities */ 2102 WPA_PUT_LE16(pos, DPP_ATTR_R_CAPABILITIES); 2103 pos += 2; 2104 WPA_PUT_LE16(pos, 1); 2105 pos += 2; 2106 auth->r_capab = auth->configurator ? DPP_CAPAB_CONFIGURATOR : 2107 DPP_CAPAB_ENROLLEE; 2108 *pos++ = auth->r_capab; 2109 2110 /* OUI, OUI type, Crypto Suite, DPP frame type */ 2111 addr[0] = wpabuf_head_u8(msg) + 2; 2112 len[0] = 3 + 1 + 1 + 1; 2113 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 2114 2115 /* Attributes before Wrapped Data */ 2116 addr[1] = attr_start; 2117 len[1] = attr_end - attr_start; 2118 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 2119 2120 siv_len = pos - clear; 2121 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", clear, siv_len); 2122 if (aes_siv_encrypt(auth->k1, auth->curve->hash_len, clear, siv_len, 2123 2, addr, len, wrapped_data) < 0) 2124 goto fail; 2125 siv_len += AES_BLOCK_SIZE; 2126 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 2127 wrapped_data, siv_len); 2128 2129 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 2130 wpabuf_put_le16(msg, siv_len); 2131 wpabuf_put_data(msg, wrapped_data, siv_len); 2132 2133 wpa_hexdump_buf(MSG_DEBUG, 2134 "DPP: Authentication Response frame attributes", msg); 2135 2136 return 0; 2137 2138 fail: 2139 return -1; 2140 } 2141 2142 2143 struct dpp_authentication * 2144 dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual, 2145 struct dpp_bootstrap_info *peer_bi, 2146 struct dpp_bootstrap_info *own_bi, 2147 unsigned int freq, const u8 *hdr, const u8 *attr_start, 2148 const u8 *wrapped_data, u16 wrapped_data_len) 2149 { 2150 EVP_PKEY *pi = NULL; 2151 EVP_PKEY_CTX *ctx = NULL; 2152 size_t secret_len; 2153 const u8 *addr[2]; 2154 size_t len[2]; 2155 u8 *unwrapped = NULL; 2156 size_t unwrapped_len = 0; 2157 const u8 *i_proto, *i_nonce, *i_capab, *i_bootstrap; 2158 u16 i_proto_len, i_nonce_len, i_capab_len, i_bootstrap_len; 2159 struct dpp_authentication *auth = NULL; 2160 size_t attr_len; 2161 2162 if (wrapped_data_len < AES_BLOCK_SIZE) 2163 return NULL; 2164 2165 attr_len = wrapped_data - 4 - attr_start; 2166 2167 auth = os_zalloc(sizeof(*auth)); 2168 if (!auth) 2169 goto fail; 2170 auth->msg_ctx = msg_ctx; 2171 auth->peer_bi = peer_bi; 2172 auth->own_bi = own_bi; 2173 auth->curve = own_bi->curve; 2174 auth->curr_freq = freq; 2175 2176 i_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_I_PROTOCOL_KEY, 2177 &i_proto_len); 2178 if (!i_proto) { 2179 wpa_printf(MSG_DEBUG, 2180 "DPP: Missing required Initiator Protocol Key attribute"); 2181 goto fail; 2182 } 2183 wpa_hexdump(MSG_MSGDUMP, "DPP: Initiator Protocol Key", 2184 i_proto, i_proto_len); 2185 2186 /* M = bR * PI */ 2187 pi = dpp_set_pubkey_point(own_bi->pubkey, i_proto, i_proto_len); 2188 if (!pi) { 2189 wpa_printf(MSG_DEBUG, "DPP: Invalid Initiator Protocol Key"); 2190 goto fail; 2191 } 2192 dpp_debug_print_key("Peer (Initiator) Protocol Key", pi); 2193 2194 ctx = EVP_PKEY_CTX_new(own_bi->pubkey, NULL); 2195 if (!ctx || 2196 EVP_PKEY_derive_init(ctx) != 1 || 2197 EVP_PKEY_derive_set_peer(ctx, pi) != 1 || 2198 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 || 2199 secret_len > DPP_MAX_SHARED_SECRET_LEN || 2200 EVP_PKEY_derive(ctx, auth->Mx, &secret_len) != 1) { 2201 wpa_printf(MSG_ERROR, 2202 "DPP: Failed to derive ECDH shared secret: %s", 2203 ERR_error_string(ERR_get_error(), NULL)); 2204 goto fail; 2205 } 2206 auth->secret_len = secret_len; 2207 EVP_PKEY_CTX_free(ctx); 2208 ctx = NULL; 2209 2210 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (M.x)", 2211 auth->Mx, auth->secret_len); 2212 2213 if (dpp_derive_k1(auth->Mx, auth->secret_len, auth->k1, 2214 auth->curve->hash_len) < 0) 2215 goto fail; 2216 2217 addr[0] = hdr; 2218 len[0] = DPP_HDR_LEN; 2219 addr[1] = attr_start; 2220 len[1] = attr_len; 2221 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 2222 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 2223 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 2224 wrapped_data, wrapped_data_len); 2225 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 2226 unwrapped = os_malloc(unwrapped_len); 2227 if (!unwrapped) 2228 goto fail; 2229 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len, 2230 wrapped_data, wrapped_data_len, 2231 2, addr, len, unwrapped) < 0) { 2232 wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed"); 2233 goto fail; 2234 } 2235 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 2236 unwrapped, unwrapped_len); 2237 2238 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 2239 wpa_printf(MSG_DEBUG, 2240 "DPP: Invalid attribute in unwrapped data"); 2241 goto fail; 2242 } 2243 2244 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE, 2245 &i_nonce_len); 2246 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) { 2247 wpa_printf(MSG_DEBUG, "DPP: Missing or invalid I-nonce"); 2248 goto fail; 2249 } 2250 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len); 2251 os_memcpy(auth->i_nonce, i_nonce, i_nonce_len); 2252 2253 i_capab = dpp_get_attr(unwrapped, unwrapped_len, 2254 DPP_ATTR_I_CAPABILITIES, 2255 &i_capab_len); 2256 if (!i_capab || i_capab_len < 1) { 2257 wpa_printf(MSG_DEBUG, "DPP: Missing or invalid I-capabilities"); 2258 goto fail; 2259 } 2260 auth->i_capab = i_capab[0]; 2261 wpa_printf(MSG_DEBUG, "DPP: I-capabilities: 0x%02x", auth->i_capab); 2262 2263 bin_clear_free(unwrapped, unwrapped_len); 2264 unwrapped = NULL; 2265 2266 switch (auth->i_capab & DPP_CAPAB_ROLE_MASK) { 2267 case DPP_CAPAB_ENROLLEE: 2268 if (!(dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR)) { 2269 wpa_printf(MSG_DEBUG, 2270 "DPP: Local policy does not allow Configurator role"); 2271 goto not_compatible; 2272 } 2273 wpa_printf(MSG_DEBUG, "DPP: Acting as Configurator"); 2274 auth->configurator = 1; 2275 break; 2276 case DPP_CAPAB_CONFIGURATOR: 2277 if (!(dpp_allowed_roles & DPP_CAPAB_ENROLLEE)) { 2278 wpa_printf(MSG_DEBUG, 2279 "DPP: Local policy does not allow Enrollee role"); 2280 goto not_compatible; 2281 } 2282 wpa_printf(MSG_DEBUG, "DPP: Acting as Enrollee"); 2283 auth->configurator = 0; 2284 break; 2285 default: 2286 wpa_printf(MSG_DEBUG, "DPP: Unexpected role in I-capabilities"); 2287 goto not_compatible; 2288 } 2289 2290 auth->peer_protocol_key = pi; 2291 pi = NULL; 2292 if (qr_mutual && !peer_bi && own_bi->type == DPP_BOOTSTRAP_QR_CODE) { 2293 char hex[SHA256_MAC_LEN * 2 + 1]; 2294 2295 wpa_printf(MSG_DEBUG, 2296 "DPP: Mutual authentication required with QR Codes, but peer info is not yet available - request more time"); 2297 if (dpp_auth_build_resp_status(auth, 2298 DPP_STATUS_RESPONSE_PENDING) < 0) 2299 goto fail; 2300 i_bootstrap = dpp_get_attr(attr_start, attr_len, 2301 DPP_ATTR_I_BOOTSTRAP_KEY_HASH, 2302 &i_bootstrap_len); 2303 if (i_bootstrap && i_bootstrap_len == SHA256_MAC_LEN) { 2304 auth->response_pending = 1; 2305 os_memcpy(auth->waiting_pubkey_hash, 2306 i_bootstrap, i_bootstrap_len); 2307 wpa_snprintf_hex(hex, sizeof(hex), i_bootstrap, 2308 i_bootstrap_len); 2309 } else { 2310 hex[0] = '\0'; 2311 } 2312 2313 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_SCAN_PEER_QR_CODE 2314 "%s", hex); 2315 return auth; 2316 } 2317 if (dpp_auth_build_resp(auth) < 0) 2318 goto fail; 2319 2320 return auth; 2321 2322 not_compatible: 2323 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE 2324 "i-capab=0x%02x", auth->i_capab); 2325 if (dpp_allowed_roles & DPP_CAPAB_CONFIGURATOR) 2326 auth->configurator = 1; 2327 else 2328 auth->configurator = 0; 2329 auth->peer_protocol_key = pi; 2330 pi = NULL; 2331 if (dpp_auth_build_resp_status(auth, DPP_STATUS_NOT_COMPATIBLE) < 0) 2332 goto fail; 2333 2334 auth->remove_on_tx_status = 1; 2335 return auth; 2336 fail: 2337 bin_clear_free(unwrapped, unwrapped_len); 2338 EVP_PKEY_free(pi); 2339 EVP_PKEY_CTX_free(ctx); 2340 dpp_auth_deinit(auth); 2341 return NULL; 2342 } 2343 2344 2345 int dpp_notify_new_qr_code(struct dpp_authentication *auth, 2346 struct dpp_bootstrap_info *peer_bi) 2347 { 2348 if (!auth || !auth->response_pending || 2349 os_memcmp(auth->waiting_pubkey_hash, peer_bi->pubkey_hash, 2350 SHA256_MAC_LEN) != 0) 2351 return 0; 2352 2353 wpa_printf(MSG_DEBUG, 2354 "DPP: New scanned QR Code has matching public key that was needed to continue DPP Authentication exchange with " 2355 MACSTR, MAC2STR(auth->peer_mac_addr)); 2356 auth->peer_bi = peer_bi; 2357 2358 if (dpp_auth_build_resp(auth) < 0) 2359 return -1; 2360 2361 return 1; 2362 } 2363 2364 2365 static struct wpabuf * dpp_auth_build_conf(struct dpp_authentication *auth) 2366 { 2367 struct wpabuf *msg; 2368 u8 i_auth[4 + DPP_MAX_HASH_LEN]; 2369 size_t i_auth_len; 2370 const u8 *addr[2]; 2371 size_t len[2], attr_len; 2372 u8 *wrapped_i_auth; 2373 u8 *attr_start, *attr_end; 2374 2375 wpa_printf(MSG_DEBUG, "DPP: Build Authentication Confirmation"); 2376 2377 i_auth_len = 4 + auth->curve->hash_len; 2378 /* Build DPP Authentication Confirmation frame attributes */ 2379 attr_len = 4 + 1 + 2 * (4 + SHA256_MAC_LEN) + 2380 4 + i_auth_len + AES_BLOCK_SIZE; 2381 msg = dpp_alloc_msg(DPP_PA_AUTHENTICATION_CONF, attr_len); 2382 if (!msg) 2383 goto fail; 2384 2385 attr_start = wpabuf_put(msg, 0); 2386 2387 /* DPP Status */ 2388 wpabuf_put_le16(msg, DPP_ATTR_STATUS); 2389 wpabuf_put_le16(msg, 1); 2390 wpabuf_put_u8(msg, DPP_STATUS_OK); 2391 2392 /* Responder Bootstrapping Key Hash */ 2393 wpabuf_put_le16(msg, DPP_ATTR_R_BOOTSTRAP_KEY_HASH); 2394 wpabuf_put_le16(msg, SHA256_MAC_LEN); 2395 wpabuf_put_data(msg, auth->peer_bi->pubkey_hash, SHA256_MAC_LEN); 2396 2397 if (auth->own_bi) { 2398 /* Mutual authentication */ 2399 /* Initiator Bootstrapping Key Hash */ 2400 wpabuf_put_le16(msg, DPP_ATTR_I_BOOTSTRAP_KEY_HASH); 2401 wpabuf_put_le16(msg, SHA256_MAC_LEN); 2402 wpabuf_put_data(msg, auth->own_bi->pubkey_hash, SHA256_MAC_LEN); 2403 } 2404 2405 attr_end = wpabuf_put(msg, 0); 2406 2407 /* OUI, OUI type, Crypto Suite, DPP frame type */ 2408 addr[0] = wpabuf_head_u8(msg) + 2; 2409 len[0] = 3 + 1 + 1 + 1; 2410 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 2411 2412 /* Attributes before Wrapped Data */ 2413 addr[1] = attr_start; 2414 len[1] = attr_end - attr_start; 2415 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 2416 2417 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 2418 wpabuf_put_le16(msg, i_auth_len + AES_BLOCK_SIZE); 2419 wrapped_i_auth = wpabuf_put(msg, i_auth_len + AES_BLOCK_SIZE); 2420 /* I-auth = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */ 2421 WPA_PUT_LE16(i_auth, DPP_ATTR_I_AUTH_TAG); 2422 WPA_PUT_LE16(&i_auth[2], auth->curve->hash_len); 2423 if (dpp_gen_i_auth(auth, i_auth + 4) < 0 || 2424 aes_siv_encrypt(auth->ke, auth->curve->hash_len, 2425 i_auth, i_auth_len, 2426 2, addr, len, wrapped_i_auth) < 0) 2427 goto fail; 2428 wpa_hexdump(MSG_DEBUG, "DPP: {I-auth}ke", 2429 wrapped_i_auth, i_auth_len + AES_BLOCK_SIZE); 2430 2431 wpa_hexdump_buf(MSG_DEBUG, 2432 "DPP: Authentication Confirmation frame attributes", 2433 msg); 2434 dpp_auth_success(auth); 2435 2436 return msg; 2437 2438 fail: 2439 return NULL; 2440 } 2441 2442 2443 static void 2444 dpp_auth_resp_rx_status(struct dpp_authentication *auth, const u8 *hdr, 2445 const u8 *attr_start, size_t attr_len, 2446 const u8 *wrapped_data, u16 wrapped_data_len, 2447 enum dpp_status_error status) 2448 { 2449 const u8 *addr[2]; 2450 size_t len[2]; 2451 u8 *unwrapped = NULL; 2452 size_t unwrapped_len = 0; 2453 const u8 *i_nonce, *r_capab; 2454 u16 i_nonce_len, r_capab_len; 2455 2456 if (status == DPP_STATUS_NOT_COMPATIBLE) { 2457 wpa_printf(MSG_DEBUG, 2458 "DPP: Responder reported incompatible roles"); 2459 } else if (status == DPP_STATUS_RESPONSE_PENDING) { 2460 wpa_printf(MSG_DEBUG, 2461 "DPP: Responder reported more time needed"); 2462 } else { 2463 wpa_printf(MSG_DEBUG, 2464 "DPP: Responder reported failure (status %d)", 2465 status); 2466 return; 2467 } 2468 2469 addr[0] = hdr; 2470 len[0] = DPP_HDR_LEN; 2471 addr[1] = attr_start; 2472 len[1] = attr_len; 2473 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 2474 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 2475 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 2476 wrapped_data, wrapped_data_len); 2477 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 2478 unwrapped = os_malloc(unwrapped_len); 2479 if (!unwrapped) 2480 goto fail; 2481 if (aes_siv_decrypt(auth->k1, auth->curve->hash_len, 2482 wrapped_data, wrapped_data_len, 2483 2, addr, len, unwrapped) < 0) { 2484 wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed"); 2485 goto fail; 2486 } 2487 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 2488 unwrapped, unwrapped_len); 2489 2490 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 2491 wpa_printf(MSG_DEBUG, 2492 "DPP: Invalid attribute in unwrapped data"); 2493 goto fail; 2494 } 2495 2496 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE, 2497 &i_nonce_len); 2498 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) { 2499 wpa_printf(MSG_DEBUG, "DPP: Missing or invalid I-nonce"); 2500 goto fail; 2501 } 2502 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len); 2503 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) { 2504 wpa_printf(MSG_DEBUG, "DPP: I-nonce mismatch"); 2505 goto fail; 2506 } 2507 2508 r_capab = dpp_get_attr(unwrapped, unwrapped_len, 2509 DPP_ATTR_R_CAPABILITIES, 2510 &r_capab_len); 2511 if (!r_capab || r_capab_len < 1) { 2512 wpa_printf(MSG_DEBUG, "DPP: Missing or invalid R-capabilities"); 2513 goto fail; 2514 } 2515 auth->r_capab = r_capab[0]; 2516 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab); 2517 if (status == DPP_STATUS_NOT_COMPATIBLE) { 2518 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_NOT_COMPATIBLE 2519 "r-capab=0x%02x", auth->r_capab); 2520 } else if (status == DPP_STATUS_RESPONSE_PENDING) { 2521 wpa_printf(MSG_DEBUG, 2522 "DPP: Continue waiting for full DPP Authentication Response"); 2523 wpa_msg(auth->msg_ctx, MSG_INFO, DPP_EVENT_RESPONSE_PENDING); 2524 } 2525 fail: 2526 bin_clear_free(unwrapped, unwrapped_len); 2527 } 2528 2529 2530 struct wpabuf * 2531 dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr, 2532 const u8 *attr_start, size_t attr_len) 2533 { 2534 EVP_PKEY *pr; 2535 EVP_PKEY_CTX *ctx = NULL; 2536 size_t secret_len; 2537 const u8 *addr[2]; 2538 size_t len[2]; 2539 u8 *unwrapped = NULL, *unwrapped2 = NULL; 2540 size_t unwrapped_len = 0, unwrapped2_len = 0; 2541 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *r_proto, 2542 *r_nonce, *i_nonce, *r_capab, *wrapped2, *r_auth; 2543 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len, 2544 r_proto_len, r_nonce_len, i_nonce_len, r_capab_len, 2545 wrapped2_len, r_auth_len; 2546 u8 r_auth2[DPP_MAX_HASH_LEN]; 2547 2548 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA, 2549 &wrapped_data_len); 2550 if (!wrapped_data) { 2551 wpa_printf(MSG_DEBUG, 2552 "DPP: Missing required Wrapped data attribute"); 2553 return NULL; 2554 } 2555 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data", 2556 wrapped_data, wrapped_data_len); 2557 2558 if (wrapped_data_len < AES_BLOCK_SIZE) 2559 return NULL; 2560 2561 attr_len = wrapped_data - 4 - attr_start; 2562 2563 r_bootstrap = dpp_get_attr(attr_start, attr_len, 2564 DPP_ATTR_R_BOOTSTRAP_KEY_HASH, 2565 &r_bootstrap_len); 2566 if (!r_bootstrap || r_bootstrap_len != SHA256_MAC_LEN) { 2567 wpa_printf(MSG_DEBUG, 2568 "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute"); 2569 return NULL; 2570 } 2571 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash", 2572 r_bootstrap, r_bootstrap_len); 2573 if (os_memcmp(r_bootstrap, auth->peer_bi->pubkey_hash, 2574 SHA256_MAC_LEN) != 0) { 2575 wpa_hexdump(MSG_DEBUG, 2576 "DPP: Expected Responder Bootstrapping Key Hash", 2577 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN); 2578 return NULL; 2579 } 2580 2581 i_bootstrap = dpp_get_attr(attr_start, attr_len, 2582 DPP_ATTR_I_BOOTSTRAP_KEY_HASH, 2583 &i_bootstrap_len); 2584 if (i_bootstrap) { 2585 if (i_bootstrap_len != SHA256_MAC_LEN) { 2586 wpa_printf(MSG_DEBUG, 2587 "DPP: Invalid Initiator Bootstrapping Key Hash attribute"); 2588 return NULL; 2589 } 2590 wpa_hexdump(MSG_MSGDUMP, 2591 "DPP: Initiator Bootstrapping Key Hash", 2592 i_bootstrap, i_bootstrap_len); 2593 if (!auth->own_bi || 2594 os_memcmp(i_bootstrap, auth->own_bi->pubkey_hash, 2595 SHA256_MAC_LEN) != 0) { 2596 wpa_printf(MSG_DEBUG, 2597 "DPP: Initiator Bootstrapping Key Hash attribute did not match"); 2598 return NULL; 2599 } 2600 } 2601 2602 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS, 2603 &status_len); 2604 if (!status || status_len < 1) { 2605 wpa_printf(MSG_DEBUG, 2606 "DPP: Missing or invalid required DPP Status attribute"); 2607 return NULL; 2608 } 2609 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]); 2610 auth->auth_resp_status = status[0]; 2611 if (status[0] != DPP_STATUS_OK) { 2612 dpp_auth_resp_rx_status(auth, hdr, attr_start, 2613 attr_len, wrapped_data, 2614 wrapped_data_len, status[0]); 2615 return NULL; 2616 } 2617 2618 r_proto = dpp_get_attr(attr_start, attr_len, DPP_ATTR_R_PROTOCOL_KEY, 2619 &r_proto_len); 2620 if (!r_proto) { 2621 wpa_printf(MSG_DEBUG, 2622 "DPP: Missing required Responder Protocol Key attribute"); 2623 return NULL; 2624 } 2625 wpa_hexdump(MSG_MSGDUMP, "DPP: Responder Protocol Key", 2626 r_proto, r_proto_len); 2627 2628 /* N = pI * PR */ 2629 pr = dpp_set_pubkey_point(auth->own_protocol_key, r_proto, r_proto_len); 2630 if (!pr) { 2631 wpa_printf(MSG_DEBUG, "DPP: Invalid Responder Protocol Key"); 2632 return NULL; 2633 } 2634 dpp_debug_print_key("Peer (Responder) Protocol Key", pr); 2635 2636 ctx = EVP_PKEY_CTX_new(auth->own_protocol_key, NULL); 2637 if (!ctx || 2638 EVP_PKEY_derive_init(ctx) != 1 || 2639 EVP_PKEY_derive_set_peer(ctx, pr) != 1 || 2640 EVP_PKEY_derive(ctx, NULL, &secret_len) != 1 || 2641 secret_len > DPP_MAX_SHARED_SECRET_LEN || 2642 EVP_PKEY_derive(ctx, auth->Nx, &secret_len) != 1) { 2643 wpa_printf(MSG_ERROR, 2644 "DPP: Failed to derive ECDH shared secret: %s", 2645 ERR_error_string(ERR_get_error(), NULL)); 2646 goto fail; 2647 } 2648 EVP_PKEY_CTX_free(ctx); 2649 ctx = NULL; 2650 auth->peer_protocol_key = pr; 2651 pr = NULL; 2652 2653 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)", 2654 auth->Nx, auth->secret_len); 2655 2656 if (dpp_derive_k2(auth->Nx, auth->secret_len, auth->k2, 2657 auth->curve->hash_len) < 0) 2658 goto fail; 2659 2660 addr[0] = hdr; 2661 len[0] = DPP_HDR_LEN; 2662 addr[1] = attr_start; 2663 len[1] = attr_len; 2664 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 2665 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 2666 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 2667 wrapped_data, wrapped_data_len); 2668 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 2669 unwrapped = os_malloc(unwrapped_len); 2670 if (!unwrapped) 2671 goto fail; 2672 if (aes_siv_decrypt(auth->k2, auth->curve->hash_len, 2673 wrapped_data, wrapped_data_len, 2674 2, addr, len, unwrapped) < 0) { 2675 wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed"); 2676 goto fail; 2677 } 2678 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 2679 unwrapped, unwrapped_len); 2680 2681 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 2682 wpa_printf(MSG_DEBUG, 2683 "DPP: Invalid attribute in unwrapped data"); 2684 goto fail; 2685 } 2686 2687 r_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_NONCE, 2688 &r_nonce_len); 2689 if (!r_nonce || r_nonce_len != auth->curve->nonce_len) { 2690 wpa_printf(MSG_DEBUG, "DPP: Missing or invalid R-nonce"); 2691 goto fail; 2692 } 2693 wpa_hexdump(MSG_DEBUG, "DPP: R-nonce", r_nonce, r_nonce_len); 2694 os_memcpy(auth->r_nonce, r_nonce, r_nonce_len); 2695 2696 i_nonce = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_NONCE, 2697 &i_nonce_len); 2698 if (!i_nonce || i_nonce_len != auth->curve->nonce_len) { 2699 wpa_printf(MSG_DEBUG, "DPP: Missing or invalid I-nonce"); 2700 goto fail; 2701 } 2702 wpa_hexdump(MSG_DEBUG, "DPP: I-nonce", i_nonce, i_nonce_len); 2703 if (os_memcmp(auth->i_nonce, i_nonce, i_nonce_len) != 0) { 2704 wpa_printf(MSG_DEBUG, "DPP: I-nonce mismatch"); 2705 goto fail; 2706 } 2707 2708 if (auth->own_bi && auth->peer_bi) { 2709 /* Mutual authentication */ 2710 if (dpp_auth_derive_l_initiator(auth) < 0) 2711 goto fail; 2712 } 2713 2714 if (dpp_derive_ke(auth, auth->ke, auth->curve->hash_len) < 0) 2715 goto fail; 2716 2717 r_capab = dpp_get_attr(unwrapped, unwrapped_len, 2718 DPP_ATTR_R_CAPABILITIES, 2719 &r_capab_len); 2720 if (!r_capab || r_capab_len < 1) { 2721 wpa_printf(MSG_DEBUG, "DPP: Missing or invalid R-capabilities"); 2722 goto fail; 2723 } 2724 auth->r_capab = r_capab[0]; 2725 wpa_printf(MSG_DEBUG, "DPP: R-capabilities: 0x%02x", auth->r_capab); 2726 if ((auth->configurator && (auth->r_capab & DPP_CAPAB_CONFIGURATOR)) || 2727 (!auth->configurator && (auth->r_capab & DPP_CAPAB_ENROLLEE))) { 2728 wpa_printf(MSG_DEBUG, "DPP: Incompatible role selection"); 2729 goto fail; 2730 } 2731 2732 wrapped2 = dpp_get_attr(unwrapped, unwrapped_len, 2733 DPP_ATTR_WRAPPED_DATA, &wrapped2_len); 2734 if (!wrapped2 || wrapped2_len < AES_BLOCK_SIZE) { 2735 wpa_printf(MSG_DEBUG, 2736 "DPP: Missing or invalid Secondary Wrapped Data"); 2737 goto fail; 2738 } 2739 2740 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 2741 wrapped2, wrapped2_len); 2742 unwrapped2_len = wrapped2_len - AES_BLOCK_SIZE; 2743 unwrapped2 = os_malloc(unwrapped2_len); 2744 if (!unwrapped2) 2745 goto fail; 2746 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len, 2747 wrapped2, wrapped2_len, 2748 0, NULL, NULL, unwrapped2) < 0) { 2749 wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed"); 2750 goto fail; 2751 } 2752 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 2753 unwrapped2, unwrapped2_len); 2754 2755 if (dpp_check_attrs(unwrapped2, unwrapped2_len) < 0) { 2756 wpa_printf(MSG_DEBUG, 2757 "DPP: Invalid attribute in secondary unwrapped data"); 2758 goto fail; 2759 } 2760 2761 r_auth = dpp_get_attr(unwrapped2, unwrapped2_len, DPP_ATTR_R_AUTH_TAG, 2762 &r_auth_len); 2763 if (!r_auth || r_auth_len != auth->curve->hash_len) { 2764 wpa_printf(MSG_DEBUG, 2765 "DPP: Missing or invalid Responder Authenticating Tag"); 2766 goto fail; 2767 } 2768 wpa_hexdump(MSG_DEBUG, "DPP: Received Responder Authenticating Tag", 2769 r_auth, r_auth_len); 2770 /* R-auth' = H(I-nonce | R-nonce | PI.x | PR.x | [BI.x |] BR.x | 0) */ 2771 if (dpp_gen_r_auth(auth, r_auth2) < 0) 2772 goto fail; 2773 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Responder Authenticating Tag", 2774 r_auth2, r_auth_len); 2775 if (os_memcmp(r_auth, r_auth2, r_auth_len) != 0) { 2776 wpa_printf(MSG_DEBUG, 2777 "DPP: Mismatching Responder Authenticating Tag"); 2778 goto fail; 2779 } 2780 2781 bin_clear_free(unwrapped, unwrapped_len); 2782 bin_clear_free(unwrapped2, unwrapped2_len); 2783 2784 return dpp_auth_build_conf(auth); 2785 2786 fail: 2787 bin_clear_free(unwrapped, unwrapped_len); 2788 bin_clear_free(unwrapped2, unwrapped2_len); 2789 EVP_PKEY_free(pr); 2790 EVP_PKEY_CTX_free(ctx); 2791 return NULL; 2792 } 2793 2794 2795 int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr, 2796 const u8 *attr_start, size_t attr_len) 2797 { 2798 const u8 *r_bootstrap, *i_bootstrap, *wrapped_data, *status, *i_auth; 2799 u16 r_bootstrap_len, i_bootstrap_len, wrapped_data_len, status_len, 2800 i_auth_len; 2801 const u8 *addr[2]; 2802 size_t len[2]; 2803 u8 *unwrapped = NULL; 2804 size_t unwrapped_len = 0; 2805 u8 i_auth2[DPP_MAX_HASH_LEN]; 2806 2807 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA, 2808 &wrapped_data_len); 2809 if (!wrapped_data) { 2810 wpa_printf(MSG_DEBUG, 2811 "DPP: Missing required Wrapped data attribute"); 2812 return -1; 2813 } 2814 wpa_hexdump(MSG_DEBUG, "DPP: Wrapped data", 2815 wrapped_data, wrapped_data_len); 2816 2817 if (wrapped_data_len < AES_BLOCK_SIZE) 2818 return -1; 2819 2820 attr_len = wrapped_data - 4 - attr_start; 2821 2822 r_bootstrap = dpp_get_attr(attr_start, attr_len, 2823 DPP_ATTR_R_BOOTSTRAP_KEY_HASH, 2824 &r_bootstrap_len); 2825 if (!r_bootstrap || r_bootstrap > wrapped_data || 2826 r_bootstrap_len != SHA256_MAC_LEN) { 2827 wpa_printf(MSG_DEBUG, 2828 "DPP: Missing or invalid required Responder Bootstrapping Key Hash attribute"); 2829 return -1; 2830 } 2831 wpa_hexdump(MSG_DEBUG, "DPP: Responder Bootstrapping Key Hash", 2832 r_bootstrap, r_bootstrap_len); 2833 if (os_memcmp(r_bootstrap, auth->own_bi->pubkey_hash, 2834 SHA256_MAC_LEN) != 0) { 2835 wpa_hexdump(MSG_DEBUG, 2836 "DPP: Expected Responder Bootstrapping Key Hash", 2837 auth->peer_bi->pubkey_hash, SHA256_MAC_LEN); 2838 return -1; 2839 } 2840 2841 i_bootstrap = dpp_get_attr(attr_start, attr_len, 2842 DPP_ATTR_I_BOOTSTRAP_KEY_HASH, 2843 &i_bootstrap_len); 2844 if (i_bootstrap) { 2845 if (i_bootstrap > wrapped_data || 2846 i_bootstrap_len != SHA256_MAC_LEN) { 2847 wpa_printf(MSG_DEBUG, 2848 "DPP: Invalid Initiator Bootstrapping Key Hash attribute"); 2849 return -1; 2850 } 2851 wpa_hexdump(MSG_MSGDUMP, 2852 "DPP: Initiator Bootstrapping Key Hash", 2853 i_bootstrap, i_bootstrap_len); 2854 if (!auth->peer_bi || 2855 os_memcmp(i_bootstrap, auth->peer_bi->pubkey_hash, 2856 SHA256_MAC_LEN) != 0) { 2857 wpa_printf(MSG_DEBUG, 2858 "DPP: Initiator Bootstrapping Key Hash attribute did not match"); 2859 return -1; 2860 } 2861 } 2862 2863 status = dpp_get_attr(attr_start, attr_len, DPP_ATTR_STATUS, 2864 &status_len); 2865 if (!status || status_len < 1) { 2866 wpa_printf(MSG_DEBUG, 2867 "DPP: Missing or invalid required DPP Status attribute"); 2868 return -1; 2869 } 2870 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]); 2871 if (status[0] != DPP_STATUS_OK) { 2872 wpa_printf(MSG_DEBUG, "DPP: Authentication failed"); 2873 return -1; 2874 } 2875 2876 addr[0] = hdr; 2877 len[0] = DPP_HDR_LEN; 2878 addr[1] = attr_start; 2879 len[1] = attr_len; 2880 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 2881 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 2882 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 2883 wrapped_data, wrapped_data_len); 2884 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 2885 unwrapped = os_malloc(unwrapped_len); 2886 if (!unwrapped) 2887 return -1; 2888 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len, 2889 wrapped_data, wrapped_data_len, 2890 2, addr, len, unwrapped) < 0) { 2891 wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed"); 2892 goto fail; 2893 } 2894 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 2895 unwrapped, unwrapped_len); 2896 2897 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 2898 wpa_printf(MSG_DEBUG, 2899 "DPP: Invalid attribute in unwrapped data"); 2900 goto fail; 2901 } 2902 2903 i_auth = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG, 2904 &i_auth_len); 2905 if (!i_auth || i_auth_len != auth->curve->hash_len) { 2906 wpa_printf(MSG_DEBUG, 2907 "DPP: Missing or invalid Initiator Authenticating Tag"); 2908 goto fail; 2909 } 2910 wpa_hexdump(MSG_DEBUG, "DPP: Received Initiator Authenticating Tag", 2911 i_auth, i_auth_len); 2912 /* I-auth' = H(R-nonce | I-nonce | PR.x | PI.x | BR.x | [BI.x |] 1) */ 2913 if (dpp_gen_i_auth(auth, i_auth2) < 0) 2914 goto fail; 2915 wpa_hexdump(MSG_DEBUG, "DPP: Calculated Initiator Authenticating Tag", 2916 i_auth2, i_auth_len); 2917 if (os_memcmp(i_auth, i_auth2, i_auth_len) != 0) { 2918 wpa_printf(MSG_DEBUG, 2919 "DPP: Mismatching Initiator Authenticating Tag"); 2920 goto fail; 2921 } 2922 2923 bin_clear_free(unwrapped, unwrapped_len); 2924 dpp_auth_success(auth); 2925 return 0; 2926 fail: 2927 bin_clear_free(unwrapped, unwrapped_len); 2928 return -1; 2929 } 2930 2931 2932 void dpp_configuration_free(struct dpp_configuration *conf) 2933 { 2934 if (!conf) 2935 return; 2936 str_clear_free(conf->passphrase); 2937 bin_clear_free(conf, sizeof(*conf)); 2938 } 2939 2940 2941 void dpp_auth_deinit(struct dpp_authentication *auth) 2942 { 2943 if (!auth) 2944 return; 2945 dpp_configuration_free(auth->conf_ap); 2946 dpp_configuration_free(auth->conf_sta); 2947 EVP_PKEY_free(auth->own_protocol_key); 2948 EVP_PKEY_free(auth->peer_protocol_key); 2949 wpabuf_free(auth->req_msg); 2950 wpabuf_free(auth->resp_msg); 2951 wpabuf_free(auth->conf_req); 2952 os_free(auth->connector); 2953 wpabuf_free(auth->net_access_key); 2954 wpabuf_free(auth->c_sign_key); 2955 #ifdef CONFIG_TESTING_OPTIONS 2956 os_free(auth->config_obj_override); 2957 os_free(auth->discovery_override); 2958 os_free(auth->groups_override); 2959 #endif /* CONFIG_TESTING_OPTIONS */ 2960 bin_clear_free(auth, sizeof(*auth)); 2961 } 2962 2963 2964 static struct wpabuf * 2965 dpp_build_conf_start(struct dpp_authentication *auth, 2966 struct dpp_configuration *conf, size_t tailroom) 2967 { 2968 struct wpabuf *buf; 2969 char ssid[6 * sizeof(conf->ssid) + 1]; 2970 2971 #ifdef CONFIG_TESTING_OPTIONS 2972 if (auth->discovery_override) 2973 tailroom += os_strlen(auth->discovery_override); 2974 #endif /* CONFIG_TESTING_OPTIONS */ 2975 2976 buf = wpabuf_alloc(200 + tailroom); 2977 if (!buf) 2978 return NULL; 2979 wpabuf_put_str(buf, "{\"wi-fi_tech\":\"infra\",\"discovery\":"); 2980 #ifdef CONFIG_TESTING_OPTIONS 2981 if (auth->discovery_override) { 2982 wpa_printf(MSG_DEBUG, "DPP: TESTING - discovery override: '%s'", 2983 auth->discovery_override); 2984 wpabuf_put_str(buf, auth->discovery_override); 2985 wpabuf_put_u8(buf, ','); 2986 return buf; 2987 } 2988 #endif /* CONFIG_TESTING_OPTIONS */ 2989 wpabuf_put_str(buf, "{\"ssid\":\""); 2990 json_escape_string(ssid, sizeof(ssid), 2991 (const char *) conf->ssid, conf->ssid_len); 2992 wpabuf_put_str(buf, ssid); 2993 wpabuf_put_str(buf, "\""); 2994 /* TODO: optional channel information */ 2995 wpabuf_put_str(buf, "},"); 2996 2997 return buf; 2998 } 2999 3000 3001 static int dpp_bn2bin_pad(const BIGNUM *bn, u8 *pos, size_t len) 3002 { 3003 int num_bytes, offset; 3004 3005 num_bytes = BN_num_bytes(bn); 3006 if ((size_t) num_bytes > len) 3007 return -1; 3008 offset = len - num_bytes; 3009 os_memset(pos, 0, offset); 3010 BN_bn2bin(bn, pos + offset); 3011 return 0; 3012 } 3013 3014 3015 static int dpp_build_jwk(struct wpabuf *buf, const char *name, EVP_PKEY *key, 3016 const char *kid, const struct dpp_curve_params *curve) 3017 { 3018 struct wpabuf *pub; 3019 const u8 *pos; 3020 char *x = NULL, *y = NULL; 3021 int ret = -1; 3022 3023 pub = dpp_get_pubkey_point(key, 0); 3024 if (!pub) 3025 goto fail; 3026 pos = wpabuf_head(pub); 3027 x = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0); 3028 pos += curve->prime_len; 3029 y = (char *) base64_url_encode(pos, curve->prime_len, NULL, 0); 3030 if (!x || !y) 3031 goto fail; 3032 3033 wpabuf_put_str(buf, "\""); 3034 wpabuf_put_str(buf, name); 3035 wpabuf_put_str(buf, "\":{\"kty\":\"EC\",\"crv\":\""); 3036 wpabuf_put_str(buf, curve->jwk_crv); 3037 wpabuf_put_str(buf, "\",\"x\":\""); 3038 wpabuf_put_str(buf, x); 3039 wpabuf_put_str(buf, "\",\"y\":\""); 3040 wpabuf_put_str(buf, y); 3041 if (kid) { 3042 wpabuf_put_str(buf, "\",\"kid\":\""); 3043 wpabuf_put_str(buf, kid); 3044 } 3045 wpabuf_put_str(buf, "\"}"); 3046 ret = 0; 3047 fail: 3048 wpabuf_free(pub); 3049 os_free(x); 3050 os_free(y); 3051 return ret; 3052 } 3053 3054 3055 static struct wpabuf * 3056 dpp_build_conf_obj_dpp(struct dpp_authentication *auth, int ap, 3057 struct dpp_configuration *conf) 3058 { 3059 struct wpabuf *buf = NULL; 3060 char *signed1 = NULL, *signed2 = NULL, *signed3 = NULL; 3061 size_t tailroom; 3062 const struct dpp_curve_params *curve; 3063 char jws_prot_hdr[100]; 3064 size_t signed1_len, signed2_len, signed3_len; 3065 struct wpabuf *dppcon = NULL; 3066 unsigned char *signature = NULL; 3067 const unsigned char *p; 3068 size_t signature_len; 3069 EVP_MD_CTX *md_ctx = NULL; 3070 ECDSA_SIG *sig = NULL; 3071 char *dot = "."; 3072 const EVP_MD *sign_md; 3073 const BIGNUM *r, *s; 3074 size_t extra_len = 1000; 3075 3076 if (!auth->conf) { 3077 wpa_printf(MSG_INFO, 3078 "DPP: No configurator specified - cannot generate DPP config object"); 3079 goto fail; 3080 } 3081 curve = auth->conf->curve; 3082 if (curve->hash_len == SHA256_MAC_LEN) { 3083 sign_md = EVP_sha256(); 3084 } else if (curve->hash_len == SHA384_MAC_LEN) { 3085 sign_md = EVP_sha384(); 3086 } else if (curve->hash_len == SHA512_MAC_LEN) { 3087 sign_md = EVP_sha512(); 3088 } else { 3089 wpa_printf(MSG_DEBUG, "DPP: Unknown signature algorithm"); 3090 goto fail; 3091 } 3092 3093 #ifdef CONFIG_TESTING_OPTIONS 3094 if (auth->groups_override) 3095 extra_len += os_strlen(auth->groups_override); 3096 #endif /* CONFIG_TESTING_OPTIONS */ 3097 3098 /* Connector (JSON dppCon object) */ 3099 dppcon = wpabuf_alloc(extra_len + 2 * auth->curve->prime_len * 4 / 3); 3100 if (!dppcon) 3101 goto fail; 3102 #ifdef CONFIG_TESTING_OPTIONS 3103 if (auth->groups_override) { 3104 wpabuf_put_u8(dppcon, '{'); 3105 if (auth->groups_override) { 3106 wpa_printf(MSG_DEBUG, 3107 "DPP: TESTING - groups override: '%s'", 3108 auth->groups_override); 3109 wpabuf_put_str(dppcon, "\"groups\":"); 3110 wpabuf_put_str(dppcon, auth->groups_override); 3111 wpabuf_put_u8(dppcon, ','); 3112 } 3113 goto skip_groups; 3114 } 3115 #endif /* CONFIG_TESTING_OPTIONS */ 3116 wpabuf_put_str(dppcon, "{\"groups\":[{\"groupId\":\"*\","); 3117 wpabuf_printf(dppcon, "\"netRole\":\"%s\"}],", ap ? "ap" : "sta"); 3118 #ifdef CONFIG_TESTING_OPTIONS 3119 skip_groups: 3120 #endif /* CONFIG_TESTING_OPTIONS */ 3121 if (dpp_build_jwk(dppcon, "netAccessKey", auth->peer_protocol_key, NULL, 3122 auth->curve) < 0) { 3123 wpa_printf(MSG_DEBUG, "DPP: Failed to build netAccessKey JWK"); 3124 goto fail; 3125 } 3126 if (conf->netaccesskey_expiry) { 3127 struct os_tm tm; 3128 3129 if (os_gmtime(conf->netaccesskey_expiry, &tm) < 0) { 3130 wpa_printf(MSG_DEBUG, 3131 "DPP: Failed to generate expiry string"); 3132 goto fail; 3133 } 3134 wpabuf_printf(dppcon, 3135 ",\"expiry\":\"%04u-%02u-%02uT%02u:%02u:%02uZ\"", 3136 tm.year, tm.month, tm.day, 3137 tm.hour, tm.min, tm.sec); 3138 } 3139 wpabuf_put_u8(dppcon, '}'); 3140 wpa_printf(MSG_DEBUG, "DPP: dppCon: %s", 3141 (const char *) wpabuf_head(dppcon)); 3142 3143 os_snprintf(jws_prot_hdr, sizeof(jws_prot_hdr), 3144 "{\"typ\":\"dppCon\",\"kid\":\"%s\",\"alg\":\"%s\"}", 3145 auth->conf->kid, curve->jws_alg); 3146 signed1 = (char *) base64_url_encode((unsigned char *) jws_prot_hdr, 3147 os_strlen(jws_prot_hdr), 3148 &signed1_len, 0); 3149 signed2 = (char *) base64_url_encode(wpabuf_head(dppcon), 3150 wpabuf_len(dppcon), 3151 &signed2_len, 0); 3152 if (!signed1 || !signed2) 3153 goto fail; 3154 3155 md_ctx = EVP_MD_CTX_create(); 3156 if (!md_ctx) 3157 goto fail; 3158 3159 ERR_clear_error(); 3160 if (EVP_DigestSignInit(md_ctx, NULL, sign_md, NULL, 3161 auth->conf->csign) != 1) { 3162 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignInit failed: %s", 3163 ERR_error_string(ERR_get_error(), NULL)); 3164 goto fail; 3165 } 3166 if (EVP_DigestSignUpdate(md_ctx, signed1, signed1_len) != 1 || 3167 EVP_DigestSignUpdate(md_ctx, dot, 1) != 1 || 3168 EVP_DigestSignUpdate(md_ctx, signed2, signed2_len) != 1) { 3169 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignUpdate failed: %s", 3170 ERR_error_string(ERR_get_error(), NULL)); 3171 goto fail; 3172 } 3173 if (EVP_DigestSignFinal(md_ctx, NULL, &signature_len) != 1) { 3174 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s", 3175 ERR_error_string(ERR_get_error(), NULL)); 3176 goto fail; 3177 } 3178 signature = os_malloc(signature_len); 3179 if (!signature) 3180 goto fail; 3181 if (EVP_DigestSignFinal(md_ctx, signature, &signature_len) != 1) { 3182 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestSignFinal failed: %s", 3183 ERR_error_string(ERR_get_error(), NULL)); 3184 goto fail; 3185 } 3186 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (DER)", 3187 signature, signature_len); 3188 /* Convert to raw coordinates r,s */ 3189 p = signature; 3190 sig = d2i_ECDSA_SIG(NULL, &p, signature_len); 3191 if (!sig) 3192 goto fail; 3193 ECDSA_SIG_get0(sig, &r, &s); 3194 if (dpp_bn2bin_pad(r, signature, curve->prime_len) < 0 || 3195 dpp_bn2bin_pad(s, signature + curve->prime_len, 3196 curve->prime_len) < 0) 3197 goto fail; 3198 signature_len = 2 * curve->prime_len; 3199 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector ECDSA signature (raw r,s)", 3200 signature, signature_len); 3201 signed3 = (char *) base64_url_encode(signature, signature_len, 3202 &signed3_len, 0); 3203 if (!signed3) 3204 goto fail; 3205 3206 tailroom = 1000; 3207 tailroom += 2 * curve->prime_len * 4 / 3 + os_strlen(auth->conf->kid); 3208 tailroom += signed1_len + signed2_len + signed3_len; 3209 buf = dpp_build_conf_start(auth, conf, tailroom); 3210 if (!buf) 3211 return NULL; 3212 3213 wpabuf_put_str(buf, "\"cred\":{\"akm\":\"dpp\",\"signedConnector\":\""); 3214 wpabuf_put_str(buf, signed1); 3215 wpabuf_put_u8(buf, '.'); 3216 wpabuf_put_str(buf, signed2); 3217 wpabuf_put_u8(buf, '.'); 3218 wpabuf_put_str(buf, signed3); 3219 wpabuf_put_str(buf, "\","); 3220 if (dpp_build_jwk(buf, "csign", auth->conf->csign, auth->conf->kid, 3221 curve) < 0) { 3222 wpa_printf(MSG_DEBUG, "DPP: Failed to build csign JWK"); 3223 goto fail; 3224 } 3225 3226 wpabuf_put_str(buf, "}}"); 3227 3228 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object", 3229 wpabuf_head(buf), wpabuf_len(buf)); 3230 3231 out: 3232 EVP_MD_CTX_destroy(md_ctx); 3233 ECDSA_SIG_free(sig); 3234 os_free(signed1); 3235 os_free(signed2); 3236 os_free(signed3); 3237 os_free(signature); 3238 wpabuf_free(dppcon); 3239 return buf; 3240 fail: 3241 wpa_printf(MSG_DEBUG, "DPP: Failed to build configuration object"); 3242 wpabuf_free(buf); 3243 buf = NULL; 3244 goto out; 3245 } 3246 3247 3248 static struct wpabuf * 3249 dpp_build_conf_obj_legacy(struct dpp_authentication *auth, int ap, 3250 struct dpp_configuration *conf) 3251 { 3252 struct wpabuf *buf; 3253 3254 buf = dpp_build_conf_start(auth, conf, 1000); 3255 if (!buf) 3256 return NULL; 3257 3258 wpabuf_put_str(buf, "\"cred\":{\"akm\":\"psk\","); 3259 if (conf->passphrase) { 3260 char pass[63 * 6 + 1]; 3261 3262 if (os_strlen(conf->passphrase) > 63) { 3263 wpabuf_free(buf); 3264 return NULL; 3265 } 3266 3267 json_escape_string(pass, sizeof(pass), conf->passphrase, 3268 os_strlen(conf->passphrase)); 3269 wpabuf_put_str(buf, "\"pass\":\""); 3270 wpabuf_put_str(buf, pass); 3271 wpabuf_put_str(buf, "\""); 3272 } else { 3273 char psk[2 * sizeof(conf->psk) + 1]; 3274 3275 wpa_snprintf_hex(psk, sizeof(psk), 3276 conf->psk, sizeof(conf->psk)); 3277 wpabuf_put_str(buf, "\"psk_hex\":\""); 3278 wpabuf_put_str(buf, psk); 3279 wpabuf_put_str(buf, "\""); 3280 } 3281 wpabuf_put_str(buf, "}}"); 3282 3283 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Configuration Object (legacy)", 3284 wpabuf_head(buf), wpabuf_len(buf)); 3285 3286 return buf; 3287 } 3288 3289 3290 static struct wpabuf * 3291 dpp_build_conf_obj(struct dpp_authentication *auth, int ap) 3292 { 3293 struct dpp_configuration *conf; 3294 3295 #ifdef CONFIG_TESTING_OPTIONS 3296 if (auth->config_obj_override) { 3297 wpa_printf(MSG_DEBUG, "DPP: Testing - Config Object override"); 3298 return wpabuf_alloc_copy(auth->config_obj_override, 3299 os_strlen(auth->config_obj_override)); 3300 } 3301 #endif /* CONFIG_TESTING_OPTIONS */ 3302 3303 conf = ap ? auth->conf_ap : auth->conf_sta; 3304 if (!conf) { 3305 wpa_printf(MSG_DEBUG, 3306 "DPP: No configuration available for Enrollee(%s) - reject configuration request", 3307 ap ? "ap" : "sta"); 3308 return NULL; 3309 } 3310 3311 if (conf->dpp) 3312 return dpp_build_conf_obj_dpp(auth, ap, conf); 3313 return dpp_build_conf_obj_legacy(auth, ap, conf); 3314 } 3315 3316 3317 static struct wpabuf * 3318 dpp_build_conf_resp(struct dpp_authentication *auth, const u8 *e_nonce, 3319 u16 e_nonce_len, int ap) 3320 { 3321 struct wpabuf *conf; 3322 size_t clear_len; 3323 struct wpabuf *clear = NULL, *msg = NULL; 3324 u8 *wrapped; 3325 const u8 *addr[1]; 3326 size_t len[1]; 3327 enum dpp_status_error status; 3328 3329 conf = dpp_build_conf_obj(auth, ap); 3330 if (conf) { 3331 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON", 3332 wpabuf_head(conf), wpabuf_len(conf)); 3333 } 3334 status = conf ? DPP_STATUS_OK : DPP_STATUS_CONFIGURE_FAILURE; 3335 3336 /* { E-nonce, configurationObject}ke */ 3337 clear_len = 4 + e_nonce_len; 3338 if (conf) 3339 clear_len += 4 + wpabuf_len(conf); 3340 clear = wpabuf_alloc(clear_len); 3341 msg = wpabuf_alloc(4 + 1 + 4 + clear_len + AES_BLOCK_SIZE); 3342 if (!clear || !msg) 3343 goto fail; 3344 3345 /* E-nonce */ 3346 wpabuf_put_le16(clear, DPP_ATTR_ENROLLEE_NONCE); 3347 wpabuf_put_le16(clear, e_nonce_len); 3348 wpabuf_put_data(clear, e_nonce, e_nonce_len); 3349 3350 if (conf) { 3351 wpabuf_put_le16(clear, DPP_ATTR_CONFIG_OBJ); 3352 wpabuf_put_le16(clear, wpabuf_len(conf)); 3353 wpabuf_put_buf(clear, conf); 3354 wpabuf_free(conf); 3355 conf = NULL; 3356 } 3357 3358 /* DPP Status */ 3359 wpabuf_put_le16(msg, DPP_ATTR_STATUS); 3360 wpabuf_put_le16(msg, 1); 3361 wpabuf_put_u8(msg, status); 3362 3363 addr[0] = wpabuf_head(msg); 3364 len[0] = wpabuf_len(msg); 3365 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]); 3366 3367 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 3368 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 3369 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 3370 3371 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 3372 if (aes_siv_encrypt(auth->ke, auth->curve->hash_len, 3373 wpabuf_head(clear), wpabuf_len(clear), 3374 1, addr, len, wrapped) < 0) 3375 goto fail; 3376 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 3377 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE); 3378 wpabuf_free(clear); 3379 clear = NULL; 3380 3381 wpa_hexdump_buf(MSG_DEBUG, 3382 "DPP: Configuration Response attributes", msg); 3383 return msg; 3384 fail: 3385 wpabuf_free(conf); 3386 wpabuf_free(clear); 3387 wpabuf_free(msg); 3388 return NULL; 3389 } 3390 3391 3392 struct wpabuf * 3393 dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start, 3394 size_t attr_len) 3395 { 3396 const u8 *wrapped_data, *e_nonce, *config_attr; 3397 u16 wrapped_data_len, e_nonce_len, config_attr_len; 3398 u8 *unwrapped = NULL; 3399 size_t unwrapped_len = 0; 3400 struct wpabuf *resp = NULL; 3401 struct json_token *root = NULL, *token; 3402 int ap; 3403 3404 if (dpp_check_attrs(attr_start, attr_len) < 0) { 3405 wpa_printf(MSG_DEBUG, 3406 "DPP: Invalid attribute in config request"); 3407 return NULL; 3408 } 3409 3410 wrapped_data = dpp_get_attr(attr_start, attr_len, DPP_ATTR_WRAPPED_DATA, 3411 &wrapped_data_len); 3412 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 3413 wpa_printf(MSG_DEBUG, 3414 "DPP: Missing or invalid required Wrapped data attribute"); 3415 return NULL; 3416 } 3417 3418 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 3419 wrapped_data, wrapped_data_len); 3420 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 3421 unwrapped = os_malloc(unwrapped_len); 3422 if (!unwrapped) 3423 return NULL; 3424 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len, 3425 wrapped_data, wrapped_data_len, 3426 0, NULL, NULL, unwrapped) < 0) { 3427 wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed"); 3428 goto fail; 3429 } 3430 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 3431 unwrapped, unwrapped_len); 3432 3433 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 3434 wpa_printf(MSG_DEBUG, 3435 "DPP: Invalid attribute in unwrapped data"); 3436 goto fail; 3437 } 3438 3439 e_nonce = dpp_get_attr(unwrapped, unwrapped_len, 3440 DPP_ATTR_ENROLLEE_NONCE, 3441 &e_nonce_len); 3442 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) { 3443 wpa_printf(MSG_DEBUG, 3444 "DPP: Missing or invalid Enrollee Nonce attribute"); 3445 goto fail; 3446 } 3447 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len); 3448 3449 config_attr = dpp_get_attr(unwrapped, unwrapped_len, 3450 DPP_ATTR_CONFIG_ATTR_OBJ, 3451 &config_attr_len); 3452 if (!config_attr) { 3453 wpa_printf(MSG_DEBUG, 3454 "DPP: Missing or invalid Config Attributes attribute"); 3455 goto fail; 3456 } 3457 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Config Attributes", 3458 config_attr, config_attr_len); 3459 3460 root = json_parse((const char *) config_attr, config_attr_len); 3461 if (!root) { 3462 wpa_printf(MSG_DEBUG, "DPP: Could not parse Config Attributes"); 3463 goto fail; 3464 } 3465 3466 token = json_get_member(root, "name"); 3467 if (!token || token->type != JSON_STRING) { 3468 wpa_printf(MSG_DEBUG, "DPP: No Config Attributes - name"); 3469 goto fail; 3470 } 3471 wpa_printf(MSG_DEBUG, "DPP: Enrollee name = '%s'", token->string); 3472 3473 token = json_get_member(root, "wi-fi_tech"); 3474 if (!token || token->type != JSON_STRING) { 3475 wpa_printf(MSG_DEBUG, "DPP: No Config Attributes - wi-fi_tech"); 3476 goto fail; 3477 } 3478 wpa_printf(MSG_DEBUG, "DPP: wi-fi_tech = '%s'", token->string); 3479 if (os_strcmp(token->string, "infra") != 0) { 3480 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech '%s'", 3481 token->string); 3482 goto fail; 3483 } 3484 3485 token = json_get_member(root, "netRole"); 3486 if (!token || token->type != JSON_STRING) { 3487 wpa_printf(MSG_DEBUG, "DPP: No Config Attributes - netRole"); 3488 goto fail; 3489 } 3490 wpa_printf(MSG_DEBUG, "DPP: netRole = '%s'", token->string); 3491 if (os_strcmp(token->string, "sta") == 0) { 3492 ap = 0; 3493 } else if (os_strcmp(token->string, "ap") == 0) { 3494 ap = 1; 3495 } else { 3496 wpa_printf(MSG_DEBUG, "DPP: Unsupported netRole '%s'", 3497 token->string); 3498 goto fail; 3499 } 3500 3501 resp = dpp_build_conf_resp(auth, e_nonce, e_nonce_len, ap); 3502 3503 fail: 3504 json_free(root); 3505 os_free(unwrapped); 3506 return resp; 3507 } 3508 3509 3510 static struct wpabuf * 3511 dpp_parse_jws_prot_hdr(const struct dpp_curve_params *curve, 3512 const u8 *prot_hdr, u16 prot_hdr_len, 3513 const EVP_MD **ret_md) 3514 { 3515 struct json_token *root, *token; 3516 struct wpabuf *kid = NULL; 3517 3518 root = json_parse((const char *) prot_hdr, prot_hdr_len); 3519 if (!root) { 3520 wpa_printf(MSG_DEBUG, 3521 "DPP: JSON parsing failed for JWS Protected Header"); 3522 goto fail; 3523 } 3524 3525 if (root->type != JSON_OBJECT) { 3526 wpa_printf(MSG_DEBUG, 3527 "DPP: JWS Protected Header root is not an object"); 3528 goto fail; 3529 } 3530 3531 token = json_get_member(root, "typ"); 3532 if (!token || token->type != JSON_STRING) { 3533 wpa_printf(MSG_DEBUG, "DPP: No typ string value found"); 3534 goto fail; 3535 } 3536 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header typ=%s", 3537 token->string); 3538 if (os_strcmp(token->string, "dppCon") != 0) { 3539 wpa_printf(MSG_DEBUG, 3540 "DPP: Unsupported JWS Protected Header typ=%s", 3541 token->string); 3542 goto fail; 3543 } 3544 3545 token = json_get_member(root, "alg"); 3546 if (!token || token->type != JSON_STRING) { 3547 wpa_printf(MSG_DEBUG, "DPP: No alg string value found"); 3548 goto fail; 3549 } 3550 wpa_printf(MSG_DEBUG, "DPP: JWS Protected Header alg=%s", 3551 token->string); 3552 if (os_strcmp(token->string, curve->jws_alg) != 0) { 3553 wpa_printf(MSG_DEBUG, 3554 "DPP: Unexpected JWS Protected Header alg=%s (expected %s based on C-sign-key)", 3555 token->string, curve->jws_alg); 3556 goto fail; 3557 } 3558 if (os_strcmp(token->string, "ES256") == 0 || 3559 os_strcmp(token->string, "BS256") == 0) 3560 *ret_md = EVP_sha256(); 3561 else if (os_strcmp(token->string, "ES384") == 0 || 3562 os_strcmp(token->string, "BS384") == 0) 3563 *ret_md = EVP_sha384(); 3564 else if (os_strcmp(token->string, "ES512") == 0 || 3565 os_strcmp(token->string, "BS512") == 0) 3566 *ret_md = EVP_sha512(); 3567 else 3568 *ret_md = NULL; 3569 if (!*ret_md) { 3570 wpa_printf(MSG_DEBUG, 3571 "DPP: Unsupported JWS Protected Header alg=%s", 3572 token->string); 3573 goto fail; 3574 } 3575 3576 kid = json_get_member_base64url(root, "kid"); 3577 if (!kid) { 3578 wpa_printf(MSG_DEBUG, "DPP: No kid string value found"); 3579 goto fail; 3580 } 3581 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWS Protected Header kid (decoded)", 3582 kid); 3583 3584 fail: 3585 json_free(root); 3586 return kid; 3587 } 3588 3589 3590 static int dpp_parse_cred_legacy(struct dpp_authentication *auth, 3591 struct json_token *cred) 3592 { 3593 struct json_token *pass, *psk_hex; 3594 3595 wpa_printf(MSG_DEBUG, "DPP: Legacy akm=psk credential"); 3596 3597 pass = json_get_member(cred, "pass"); 3598 psk_hex = json_get_member(cred, "psk_hex"); 3599 3600 if (pass && pass->type == JSON_STRING) { 3601 size_t len = os_strlen(pass->string); 3602 3603 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: Legacy passphrase", 3604 pass->string, len); 3605 if (len < 8 || len > 63) 3606 return -1; 3607 os_strlcpy(auth->passphrase, pass->string, 3608 sizeof(auth->passphrase)); 3609 } else if (psk_hex && psk_hex->type == JSON_STRING) { 3610 if (os_strlen(psk_hex->string) != PMK_LEN * 2 || 3611 hexstr2bin(psk_hex->string, auth->psk, PMK_LEN) < 0) { 3612 wpa_printf(MSG_DEBUG, "DPP: Invalid psk_hex encoding"); 3613 return -1; 3614 } 3615 wpa_hexdump_key(MSG_DEBUG, "DPP: Legacy PSK", 3616 auth->psk, PMK_LEN); 3617 auth->psk_set = 1; 3618 } else { 3619 wpa_printf(MSG_DEBUG, "DPP: No pass or psk_hex strings found"); 3620 return -1; 3621 } 3622 3623 return 0; 3624 } 3625 3626 3627 static EVP_PKEY * dpp_parse_jwk(struct json_token *jwk, 3628 const struct dpp_curve_params **key_curve) 3629 { 3630 struct json_token *token; 3631 const struct dpp_curve_params *curve; 3632 struct wpabuf *x = NULL, *y = NULL; 3633 EC_GROUP *group; 3634 EVP_PKEY *pkey = NULL; 3635 3636 token = json_get_member(jwk, "kty"); 3637 if (!token || token->type != JSON_STRING) { 3638 wpa_printf(MSG_DEBUG, "DPP: No kty in JWK"); 3639 goto fail; 3640 } 3641 if (os_strcmp(token->string, "EC") != 0) { 3642 wpa_printf(MSG_DEBUG, "DPP: Unexpected JWK kty '%s", 3643 token->string); 3644 goto fail; 3645 } 3646 3647 token = json_get_member(jwk, "crv"); 3648 if (!token || token->type != JSON_STRING) { 3649 wpa_printf(MSG_DEBUG, "DPP: No crv in JWK"); 3650 goto fail; 3651 } 3652 curve = dpp_get_curve_jwk_crv(token->string); 3653 if (!curve) { 3654 wpa_printf(MSG_DEBUG, "DPP: Unsupported JWK crv '%s'", 3655 token->string); 3656 goto fail; 3657 } 3658 3659 x = json_get_member_base64url(jwk, "x"); 3660 if (!x) { 3661 wpa_printf(MSG_DEBUG, "DPP: No x in JWK"); 3662 goto fail; 3663 } 3664 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK x", x); 3665 if (wpabuf_len(x) != curve->prime_len) { 3666 wpa_printf(MSG_DEBUG, 3667 "DPP: Unexpected JWK x length %u (expected %u for curve %s)", 3668 (unsigned int) wpabuf_len(x), 3669 (unsigned int) curve->prime_len, curve->name); 3670 goto fail; 3671 } 3672 3673 y = json_get_member_base64url(jwk, "y"); 3674 if (!y) { 3675 wpa_printf(MSG_DEBUG, "DPP: No y in JWK"); 3676 goto fail; 3677 } 3678 wpa_hexdump_buf(MSG_DEBUG, "DPP: JWK y", y); 3679 if (wpabuf_len(y) != curve->prime_len) { 3680 wpa_printf(MSG_DEBUG, 3681 "DPP: Unexpected JWK y length %u (expected %u for curve %s)", 3682 (unsigned int) wpabuf_len(y), 3683 (unsigned int) curve->prime_len, curve->name); 3684 goto fail; 3685 } 3686 3687 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name)); 3688 if (!group) { 3689 wpa_printf(MSG_DEBUG, "DPP: Could not prepare group for JWK"); 3690 goto fail; 3691 } 3692 3693 pkey = dpp_set_pubkey_point_group(group, wpabuf_head(x), wpabuf_head(y), 3694 wpabuf_len(x)); 3695 *key_curve = curve; 3696 3697 fail: 3698 wpabuf_free(x); 3699 wpabuf_free(y); 3700 3701 return pkey; 3702 } 3703 3704 3705 int dpp_key_expired(const char *timestamp, os_time_t *expiry) 3706 { 3707 struct os_time now; 3708 unsigned int year, month, day, hour, min, sec; 3709 os_time_t utime; 3710 const char *pos; 3711 3712 /* ISO 8601 date and time: 3713 * <date>T<time> 3714 * YYYY-MM-DDTHH:MM:SSZ 3715 * YYYY-MM-DDTHH:MM:SS+03:00 3716 */ 3717 if (os_strlen(timestamp) < 19) { 3718 wpa_printf(MSG_DEBUG, 3719 "DPP: Too short timestamp - assume expired key"); 3720 return 1; 3721 } 3722 if (sscanf(timestamp, "%04u-%02u-%02uT%02u:%02u:%02u", 3723 &year, &month, &day, &hour, &min, &sec) != 6) { 3724 wpa_printf(MSG_DEBUG, 3725 "DPP: Failed to parse expiration day - assume expired key"); 3726 return 1; 3727 } 3728 3729 if (os_mktime(year, month, day, hour, min, sec, &utime) < 0) { 3730 wpa_printf(MSG_DEBUG, 3731 "DPP: Invalid date/time information - assume expired key"); 3732 return 1; 3733 } 3734 3735 pos = timestamp + 19; 3736 if (*pos == 'Z' || *pos == '\0') { 3737 /* In UTC - no need to adjust */ 3738 } else if (*pos == '-' || *pos == '+') { 3739 int items; 3740 3741 /* Adjust local time to UTC */ 3742 items = sscanf(pos + 1, "%02u:%02u", &hour, &min); 3743 if (items < 1) { 3744 wpa_printf(MSG_DEBUG, 3745 "DPP: Invalid time zone designator (%s) - assume expired key", 3746 pos); 3747 return 1; 3748 } 3749 if (*pos == '-') 3750 utime += 3600 * hour; 3751 if (*pos == '+') 3752 utime -= 3600 * hour; 3753 if (items > 1) { 3754 if (*pos == '-') 3755 utime += 60 * min; 3756 if (*pos == '+') 3757 utime -= 60 * min; 3758 } 3759 } else { 3760 wpa_printf(MSG_DEBUG, 3761 "DPP: Invalid time zone designator (%s) - assume expired key", 3762 pos); 3763 return 1; 3764 } 3765 if (expiry) 3766 *expiry = utime; 3767 3768 if (os_get_time(&now) < 0) { 3769 wpa_printf(MSG_DEBUG, 3770 "DPP: Cannot get current time - assume expired key"); 3771 return 1; 3772 } 3773 3774 if (now.sec > utime) { 3775 wpa_printf(MSG_DEBUG, "DPP: Key has expired (%lu < %lu)", 3776 utime, now.sec); 3777 return 1; 3778 } 3779 3780 return 0; 3781 } 3782 3783 3784 static int dpp_parse_connector(struct dpp_authentication *auth, 3785 const unsigned char *payload, 3786 u16 payload_len) 3787 { 3788 struct json_token *root, *groups, *netkey, *token; 3789 int ret = -1; 3790 EVP_PKEY *key = NULL; 3791 const struct dpp_curve_params *curve; 3792 unsigned int rules = 0; 3793 3794 root = json_parse((const char *) payload, payload_len); 3795 if (!root) { 3796 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed"); 3797 goto fail; 3798 } 3799 3800 groups = json_get_member(root, "groups"); 3801 if (!groups || groups->type != JSON_ARRAY) { 3802 wpa_printf(MSG_DEBUG, "DPP: No groups array found"); 3803 goto skip_groups; 3804 } 3805 for (token = groups->child; token; token = token->sibling) { 3806 struct json_token *id, *role; 3807 3808 id = json_get_member(token, "groupId"); 3809 if (!id || id->type != JSON_STRING) { 3810 wpa_printf(MSG_DEBUG, "DPP: Missing groupId string"); 3811 goto fail; 3812 } 3813 3814 role = json_get_member(token, "netRole"); 3815 if (!role || role->type != JSON_STRING) { 3816 wpa_printf(MSG_DEBUG, "DPP: Missing netRole string"); 3817 goto fail; 3818 } 3819 wpa_printf(MSG_DEBUG, 3820 "DPP: connector group: groupId='%s' netRole='%s'", 3821 id->string, role->string); 3822 rules++; 3823 } 3824 skip_groups: 3825 3826 if (!rules) { 3827 wpa_printf(MSG_DEBUG, 3828 "DPP: Connector includes no groups"); 3829 goto fail; 3830 } 3831 3832 token = json_get_member(root, "expiry"); 3833 if (!token || token->type != JSON_STRING) { 3834 wpa_printf(MSG_DEBUG, 3835 "DPP: No expiry string found - connector does not expire"); 3836 } else { 3837 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string); 3838 if (dpp_key_expired(token->string, 3839 &auth->net_access_key_expiry)) { 3840 wpa_printf(MSG_DEBUG, 3841 "DPP: Connector (netAccessKey) has expired"); 3842 goto fail; 3843 } 3844 } 3845 3846 netkey = json_get_member(root, "netAccessKey"); 3847 if (!netkey || netkey->type != JSON_OBJECT) { 3848 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found"); 3849 goto fail; 3850 } 3851 3852 key = dpp_parse_jwk(netkey, &curve); 3853 if (!key) 3854 goto fail; 3855 dpp_debug_print_key("DPP: Received netAccessKey", key); 3856 3857 if (EVP_PKEY_cmp(key, auth->own_protocol_key) != 1) { 3858 wpa_printf(MSG_DEBUG, 3859 "DPP: netAccessKey in connector does not match own protocol key"); 3860 #ifdef CONFIG_TESTING_OPTIONS 3861 if (auth->ignore_netaccesskey_mismatch) { 3862 wpa_printf(MSG_DEBUG, 3863 "DPP: TESTING - skip netAccessKey mismatch"); 3864 } else { 3865 goto fail; 3866 } 3867 #else /* CONFIG_TESTING_OPTIONS */ 3868 goto fail; 3869 #endif /* CONFIG_TESTING_OPTIONS */ 3870 } 3871 3872 ret = 0; 3873 fail: 3874 EVP_PKEY_free(key); 3875 json_free(root); 3876 return ret; 3877 } 3878 3879 3880 static int dpp_check_pubkey_match(EVP_PKEY *pub, struct wpabuf *r_hash) 3881 { 3882 struct wpabuf *uncomp; 3883 int res; 3884 u8 hash[SHA256_MAC_LEN]; 3885 const u8 *addr[1]; 3886 size_t len[1]; 3887 3888 if (wpabuf_len(r_hash) != SHA256_MAC_LEN) 3889 return -1; 3890 uncomp = dpp_get_pubkey_point(pub, 1); 3891 if (!uncomp) 3892 return -1; 3893 addr[0] = wpabuf_head(uncomp); 3894 len[0] = wpabuf_len(uncomp); 3895 wpa_hexdump(MSG_DEBUG, "DPP: Uncompressed public key", 3896 addr[0], len[0]); 3897 res = sha256_vector(1, addr, len, hash); 3898 wpabuf_free(uncomp); 3899 if (res < 0) 3900 return -1; 3901 if (os_memcmp(hash, wpabuf_head(r_hash), SHA256_MAC_LEN) != 0) { 3902 wpa_printf(MSG_DEBUG, 3903 "DPP: Received hash value does not match calculated public key hash value"); 3904 wpa_hexdump(MSG_DEBUG, "DPP: Calculated hash", 3905 hash, SHA256_MAC_LEN); 3906 return -1; 3907 } 3908 return 0; 3909 } 3910 3911 3912 static void dpp_copy_csign(struct dpp_authentication *auth, EVP_PKEY *csign) 3913 { 3914 unsigned char *der = NULL; 3915 int der_len; 3916 3917 der_len = i2d_PUBKEY(csign, &der); 3918 if (der_len <= 0) 3919 return; 3920 wpabuf_free(auth->c_sign_key); 3921 auth->c_sign_key = wpabuf_alloc_copy(der, der_len); 3922 OPENSSL_free(der); 3923 } 3924 3925 3926 static void dpp_copy_netaccesskey(struct dpp_authentication *auth) 3927 { 3928 unsigned char *der = NULL; 3929 int der_len; 3930 EC_KEY *eckey; 3931 3932 eckey = EVP_PKEY_get1_EC_KEY(auth->own_protocol_key); 3933 if (!eckey) 3934 return; 3935 3936 der_len = i2d_ECPrivateKey(eckey, &der); 3937 if (der_len <= 0) { 3938 EC_KEY_free(eckey); 3939 return; 3940 } 3941 wpabuf_free(auth->net_access_key); 3942 auth->net_access_key = wpabuf_alloc_copy(der, der_len); 3943 OPENSSL_free(der); 3944 EC_KEY_free(eckey); 3945 } 3946 3947 3948 struct dpp_signed_connector_info { 3949 unsigned char *payload; 3950 size_t payload_len; 3951 }; 3952 3953 static int 3954 dpp_process_signed_connector(struct dpp_signed_connector_info *info, 3955 EVP_PKEY *csign_pub, const char *connector) 3956 { 3957 int ret = -1; 3958 const char *pos, *end, *signed_start, *signed_end; 3959 struct wpabuf *kid = NULL; 3960 unsigned char *prot_hdr = NULL, *signature = NULL; 3961 size_t prot_hdr_len = 0, signature_len = 0; 3962 const EVP_MD *sign_md = NULL; 3963 unsigned char *der = NULL; 3964 int der_len; 3965 int res; 3966 EVP_MD_CTX *md_ctx = NULL; 3967 ECDSA_SIG *sig = NULL; 3968 BIGNUM *r = NULL, *s = NULL; 3969 const struct dpp_curve_params *curve; 3970 EC_KEY *eckey; 3971 const EC_GROUP *group; 3972 int nid; 3973 3974 eckey = EVP_PKEY_get1_EC_KEY(csign_pub); 3975 if (!eckey) 3976 goto fail; 3977 group = EC_KEY_get0_group(eckey); 3978 if (!group) 3979 goto fail; 3980 nid = EC_GROUP_get_curve_name(group); 3981 curve = dpp_get_curve_nid(nid); 3982 if (!curve) 3983 goto fail; 3984 wpa_printf(MSG_DEBUG, "DPP: C-sign-key group: %s", curve->jwk_crv); 3985 os_memset(info, 0, sizeof(*info)); 3986 3987 signed_start = pos = connector; 3988 end = os_strchr(pos, '.'); 3989 if (!end) { 3990 wpa_printf(MSG_DEBUG, "DPP: Missing dot(1) in signedConnector"); 3991 goto fail; 3992 } 3993 prot_hdr = base64_url_decode((const unsigned char *) pos, 3994 end - pos, &prot_hdr_len); 3995 if (!prot_hdr) { 3996 wpa_printf(MSG_DEBUG, 3997 "DPP: Failed to base64url decode signedConnector JWS Protected Header"); 3998 goto fail; 3999 } 4000 wpa_hexdump_ascii(MSG_DEBUG, 4001 "DPP: signedConnector - JWS Protected Header", 4002 prot_hdr, prot_hdr_len); 4003 kid = dpp_parse_jws_prot_hdr(curve, prot_hdr, prot_hdr_len, &sign_md); 4004 if (!kid) 4005 goto fail; 4006 if (wpabuf_len(kid) != SHA256_MAC_LEN) { 4007 wpa_printf(MSG_DEBUG, 4008 "DPP: Unexpected signedConnector JWS Protected Header kid length: %u (expected %u)", 4009 (unsigned int) wpabuf_len(kid), SHA256_MAC_LEN); 4010 goto fail; 4011 } 4012 4013 pos = end + 1; 4014 end = os_strchr(pos, '.'); 4015 if (!end) { 4016 wpa_printf(MSG_DEBUG, 4017 "DPP: Missing dot(2) in signedConnector"); 4018 goto fail; 4019 } 4020 signed_end = end - 1; 4021 info->payload = base64_url_decode((const unsigned char *) pos, 4022 end - pos, &info->payload_len); 4023 if (!info->payload) { 4024 wpa_printf(MSG_DEBUG, 4025 "DPP: Failed to base64url decode signedConnector JWS Payload"); 4026 goto fail; 4027 } 4028 wpa_hexdump_ascii(MSG_DEBUG, 4029 "DPP: signedConnector - JWS Payload", 4030 info->payload, info->payload_len); 4031 pos = end + 1; 4032 signature = base64_url_decode((const unsigned char *) pos, 4033 os_strlen(pos), &signature_len); 4034 if (!signature) { 4035 wpa_printf(MSG_DEBUG, 4036 "DPP: Failed to base64url decode signedConnector signature"); 4037 goto fail; 4038 } 4039 wpa_hexdump(MSG_DEBUG, "DPP: signedConnector - signature", 4040 signature, signature_len); 4041 4042 if (dpp_check_pubkey_match(csign_pub, kid) < 0) 4043 goto fail; 4044 4045 if (signature_len & 0x01) { 4046 wpa_printf(MSG_DEBUG, 4047 "DPP: Unexpected signedConnector signature length (%d)", 4048 (int) signature_len); 4049 goto fail; 4050 } 4051 4052 /* JWS Signature encodes the signature (r,s) as two octet strings. Need 4053 * to convert that to DER encoded ECDSA_SIG for OpenSSL EVP routines. */ 4054 r = BN_bin2bn(signature, signature_len / 2, NULL); 4055 s = BN_bin2bn(signature + signature_len / 2, signature_len / 2, NULL); 4056 sig = ECDSA_SIG_new(); 4057 if (!r || !s || !sig || ECDSA_SIG_set0(sig, r, s) != 1) 4058 goto fail; 4059 r = NULL; 4060 s = NULL; 4061 4062 der_len = i2d_ECDSA_SIG(sig, &der); 4063 if (der_len <= 0) { 4064 wpa_printf(MSG_DEBUG, "DPP: Could not DER encode signature"); 4065 goto fail; 4066 } 4067 wpa_hexdump(MSG_DEBUG, "DPP: DER encoded signature", der, der_len); 4068 md_ctx = EVP_MD_CTX_create(); 4069 if (!md_ctx) 4070 goto fail; 4071 4072 ERR_clear_error(); 4073 if (EVP_DigestVerifyInit(md_ctx, NULL, sign_md, NULL, csign_pub) != 1) { 4074 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyInit failed: %s", 4075 ERR_error_string(ERR_get_error(), NULL)); 4076 goto fail; 4077 } 4078 if (EVP_DigestVerifyUpdate(md_ctx, signed_start, 4079 signed_end - signed_start + 1) != 1) { 4080 wpa_printf(MSG_DEBUG, "DPP: EVP_DigestVerifyUpdate failed: %s", 4081 ERR_error_string(ERR_get_error(), NULL)); 4082 goto fail; 4083 } 4084 res = EVP_DigestVerifyFinal(md_ctx, der, der_len); 4085 if (res != 1) { 4086 wpa_printf(MSG_DEBUG, 4087 "DPP: EVP_DigestVerifyFinal failed (res=%d): %s", 4088 res, ERR_error_string(ERR_get_error(), NULL)); 4089 goto fail; 4090 } 4091 4092 ret = 0; 4093 fail: 4094 EC_KEY_free(eckey); 4095 EVP_MD_CTX_destroy(md_ctx); 4096 os_free(prot_hdr); 4097 wpabuf_free(kid); 4098 os_free(signature); 4099 ECDSA_SIG_free(sig); 4100 BN_free(r); 4101 BN_free(s); 4102 OPENSSL_free(der); 4103 return ret; 4104 } 4105 4106 4107 static int dpp_parse_cred_dpp(struct dpp_authentication *auth, 4108 struct json_token *cred) 4109 { 4110 struct dpp_signed_connector_info info; 4111 struct json_token *token, *csign; 4112 int ret = -1; 4113 EVP_PKEY *csign_pub = NULL; 4114 const struct dpp_curve_params *key_curve = NULL; 4115 const char *signed_connector; 4116 4117 os_memset(&info, 0, sizeof(info)); 4118 4119 wpa_printf(MSG_DEBUG, "DPP: Connector credential"); 4120 4121 csign = json_get_member(cred, "csign"); 4122 if (!csign || csign->type != JSON_OBJECT) { 4123 wpa_printf(MSG_DEBUG, "DPP: No csign JWK in JSON"); 4124 goto fail; 4125 } 4126 4127 csign_pub = dpp_parse_jwk(csign, &key_curve); 4128 if (!csign_pub) { 4129 wpa_printf(MSG_DEBUG, "DPP: Failed to parse csign JWK"); 4130 goto fail; 4131 } 4132 dpp_debug_print_key("DPP: Received C-sign-key", csign_pub); 4133 4134 token = json_get_member(cred, "signedConnector"); 4135 if (!token || token->type != JSON_STRING) { 4136 wpa_printf(MSG_DEBUG, "DPP: No signedConnector string found"); 4137 goto fail; 4138 } 4139 wpa_hexdump_ascii(MSG_DEBUG, "DPP: signedConnector", 4140 token->string, os_strlen(token->string)); 4141 signed_connector = token->string; 4142 4143 if (os_strchr(signed_connector, '"') || 4144 os_strchr(signed_connector, '\n')) { 4145 wpa_printf(MSG_DEBUG, 4146 "DPP: Unexpected character in signedConnector"); 4147 goto fail; 4148 } 4149 4150 if (dpp_process_signed_connector(&info, csign_pub, 4151 signed_connector) < 0) 4152 goto fail; 4153 4154 if (dpp_parse_connector(auth, info.payload, info.payload_len) < 0) { 4155 wpa_printf(MSG_DEBUG, "DPP: Failed to parse connector"); 4156 goto fail; 4157 } 4158 4159 os_free(auth->connector); 4160 auth->connector = os_strdup(signed_connector); 4161 4162 dpp_copy_csign(auth, csign_pub); 4163 dpp_copy_netaccesskey(auth); 4164 4165 ret = 0; 4166 fail: 4167 EVP_PKEY_free(csign_pub); 4168 os_free(info.payload); 4169 return ret; 4170 } 4171 4172 4173 static int dpp_parse_conf_obj(struct dpp_authentication *auth, 4174 const u8 *conf_obj, u16 conf_obj_len) 4175 { 4176 int ret = -1; 4177 struct json_token *root, *token, *discovery, *cred; 4178 4179 root = json_parse((const char *) conf_obj, conf_obj_len); 4180 if (!root) 4181 return -1; 4182 if (root->type != JSON_OBJECT) { 4183 wpa_printf(MSG_DEBUG, "DPP: JSON root is not an object"); 4184 goto fail; 4185 } 4186 4187 token = json_get_member(root, "wi-fi_tech"); 4188 if (!token || token->type != JSON_STRING) { 4189 wpa_printf(MSG_DEBUG, "DPP: No wi-fi_tech string value found"); 4190 goto fail; 4191 } 4192 if (os_strcmp(token->string, "infra") != 0) { 4193 wpa_printf(MSG_DEBUG, "DPP: Unsupported wi-fi_tech value: '%s'", 4194 token->string); 4195 goto fail; 4196 } 4197 4198 discovery = json_get_member(root, "discovery"); 4199 if (!discovery || discovery->type != JSON_OBJECT) { 4200 wpa_printf(MSG_DEBUG, "DPP: No discovery object in JSON"); 4201 goto fail; 4202 } 4203 4204 token = json_get_member(discovery, "ssid"); 4205 if (!token || token->type != JSON_STRING) { 4206 wpa_printf(MSG_DEBUG, 4207 "DPP: No discovery::ssid string value found"); 4208 goto fail; 4209 } 4210 wpa_hexdump_ascii(MSG_DEBUG, "DPP: discovery::ssid", 4211 token->string, os_strlen(token->string)); 4212 if (os_strlen(token->string) > SSID_MAX_LEN) { 4213 wpa_printf(MSG_DEBUG, 4214 "DPP: Too long discovery::ssid string value"); 4215 goto fail; 4216 } 4217 auth->ssid_len = os_strlen(token->string); 4218 os_memcpy(auth->ssid, token->string, auth->ssid_len); 4219 4220 cred = json_get_member(root, "cred"); 4221 if (!cred || cred->type != JSON_OBJECT) { 4222 wpa_printf(MSG_DEBUG, "DPP: No cred object in JSON"); 4223 goto fail; 4224 } 4225 4226 token = json_get_member(cred, "akm"); 4227 if (!token || token->type != JSON_STRING) { 4228 wpa_printf(MSG_DEBUG, 4229 "DPP: No cred::akm string value found"); 4230 goto fail; 4231 } 4232 if (os_strcmp(token->string, "psk") == 0) { 4233 if (dpp_parse_cred_legacy(auth, cred) < 0) 4234 goto fail; 4235 } else if (os_strcmp(token->string, "dpp") == 0) { 4236 if (dpp_parse_cred_dpp(auth, cred) < 0) 4237 goto fail; 4238 } else { 4239 wpa_printf(MSG_DEBUG, "DPP: Unsupported akm: %s", 4240 token->string); 4241 goto fail; 4242 } 4243 4244 wpa_printf(MSG_DEBUG, "DPP: JSON parsing completed successfully"); 4245 ret = 0; 4246 fail: 4247 json_free(root); 4248 return ret; 4249 } 4250 4251 4252 int dpp_conf_resp_rx(struct dpp_authentication *auth, 4253 const struct wpabuf *resp) 4254 { 4255 const u8 *wrapped_data, *e_nonce, *status, *conf_obj; 4256 u16 wrapped_data_len, e_nonce_len, status_len, conf_obj_len; 4257 const u8 *addr[1]; 4258 size_t len[1]; 4259 u8 *unwrapped = NULL; 4260 size_t unwrapped_len = 0; 4261 int ret = -1; 4262 4263 if (dpp_check_attrs(wpabuf_head(resp), wpabuf_len(resp)) < 0) { 4264 wpa_printf(MSG_DEBUG, 4265 "DPP: Invalid attribute in config response"); 4266 return -1; 4267 } 4268 4269 wrapped_data = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp), 4270 DPP_ATTR_WRAPPED_DATA, 4271 &wrapped_data_len); 4272 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 4273 wpa_printf(MSG_DEBUG, 4274 "DPP: Missing or invalid required Wrapped data attribute"); 4275 return -1; 4276 } 4277 4278 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 4279 wrapped_data, wrapped_data_len); 4280 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 4281 unwrapped = os_malloc(unwrapped_len); 4282 if (!unwrapped) 4283 return -1; 4284 4285 addr[0] = wpabuf_head(resp); 4286 len[0] = wrapped_data - 4 - (const u8 *) wpabuf_head(resp); 4287 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD", addr[0], len[0]); 4288 4289 if (aes_siv_decrypt(auth->ke, auth->curve->hash_len, 4290 wrapped_data, wrapped_data_len, 4291 1, addr, len, unwrapped) < 0) { 4292 wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed"); 4293 goto fail; 4294 } 4295 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 4296 unwrapped, unwrapped_len); 4297 4298 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 4299 wpa_printf(MSG_DEBUG, 4300 "DPP: Invalid attribute in unwrapped data"); 4301 goto fail; 4302 } 4303 4304 e_nonce = dpp_get_attr(unwrapped, unwrapped_len, 4305 DPP_ATTR_ENROLLEE_NONCE, 4306 &e_nonce_len); 4307 if (!e_nonce || e_nonce_len != auth->curve->nonce_len) { 4308 wpa_printf(MSG_DEBUG, 4309 "DPP: Missing or invalid Enrollee Nonce attribute"); 4310 goto fail; 4311 } 4312 wpa_hexdump(MSG_DEBUG, "DPP: Enrollee Nonce", e_nonce, e_nonce_len); 4313 if (os_memcmp(e_nonce, auth->e_nonce, e_nonce_len) != 0) { 4314 wpa_printf(MSG_DEBUG, "Enrollee Nonce mismatch"); 4315 goto fail; 4316 } 4317 4318 status = dpp_get_attr(wpabuf_head(resp), wpabuf_len(resp), 4319 DPP_ATTR_STATUS, &status_len); 4320 if (!status || status_len < 1) { 4321 wpa_printf(MSG_DEBUG, 4322 "DPP: Missing or invalid required DPP Status attribute"); 4323 goto fail; 4324 } 4325 wpa_printf(MSG_DEBUG, "DPP: Status %u", status[0]); 4326 if (status[0] != DPP_STATUS_OK) { 4327 wpa_printf(MSG_DEBUG, "DPP: Configuration failed"); 4328 goto fail; 4329 } 4330 4331 conf_obj = dpp_get_attr(unwrapped, unwrapped_len, 4332 DPP_ATTR_CONFIG_OBJ, &conf_obj_len); 4333 if (!conf_obj) { 4334 wpa_printf(MSG_DEBUG, 4335 "DPP: Missing required Configuration Object attribute"); 4336 goto fail; 4337 } 4338 wpa_hexdump_ascii(MSG_DEBUG, "DPP: configurationObject JSON", 4339 conf_obj, conf_obj_len); 4340 if (dpp_parse_conf_obj(auth, conf_obj, conf_obj_len) < 0) 4341 goto fail; 4342 4343 ret = 0; 4344 4345 fail: 4346 os_free(unwrapped); 4347 return ret; 4348 } 4349 4350 4351 void dpp_configurator_free(struct dpp_configurator *conf) 4352 { 4353 if (!conf) 4354 return; 4355 EVP_PKEY_free(conf->csign); 4356 os_free(conf->kid); 4357 os_free(conf); 4358 } 4359 4360 4361 struct dpp_configurator * 4362 dpp_keygen_configurator(const char *curve, const u8 *privkey, 4363 size_t privkey_len) 4364 { 4365 struct dpp_configurator *conf; 4366 struct wpabuf *csign_pub = NULL; 4367 u8 kid_hash[SHA256_MAC_LEN]; 4368 const u8 *addr[1]; 4369 size_t len[1]; 4370 4371 conf = os_zalloc(sizeof(*conf)); 4372 if (!conf) 4373 return NULL; 4374 4375 if (!curve) { 4376 conf->curve = &dpp_curves[0]; 4377 } else { 4378 conf->curve = dpp_get_curve_name(curve); 4379 if (!conf->curve) { 4380 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", 4381 curve); 4382 return NULL; 4383 } 4384 } 4385 if (privkey) 4386 conf->csign = dpp_set_keypair(&conf->curve, privkey, 4387 privkey_len); 4388 else 4389 conf->csign = dpp_gen_keypair(conf->curve); 4390 if (!conf->csign) 4391 goto fail; 4392 conf->own = 1; 4393 4394 csign_pub = dpp_get_pubkey_point(conf->csign, 1); 4395 if (!csign_pub) { 4396 wpa_printf(MSG_INFO, "DPP: Failed to extract C-sign-key"); 4397 goto fail; 4398 } 4399 4400 /* kid = SHA256(ANSI X9.63 uncompressed C-sign-key) */ 4401 addr[0] = wpabuf_head(csign_pub); 4402 len[0] = wpabuf_len(csign_pub); 4403 if (sha256_vector(1, addr, len, kid_hash) < 0) { 4404 wpa_printf(MSG_DEBUG, 4405 "DPP: Failed to derive kid for C-sign-key"); 4406 goto fail; 4407 } 4408 4409 conf->kid = (char *) base64_url_encode(kid_hash, sizeof(kid_hash), 4410 NULL, 0); 4411 if (!conf->kid) 4412 goto fail; 4413 out: 4414 wpabuf_free(csign_pub); 4415 return conf; 4416 fail: 4417 dpp_configurator_free(conf); 4418 conf = NULL; 4419 goto out; 4420 } 4421 4422 4423 int dpp_configurator_own_config(struct dpp_authentication *auth, 4424 const char *curve) 4425 { 4426 struct wpabuf *conf_obj; 4427 int ret = -1; 4428 4429 if (!auth->conf) { 4430 wpa_printf(MSG_DEBUG, "DPP: No configurator specified"); 4431 return -1; 4432 } 4433 4434 if (!curve) { 4435 auth->curve = &dpp_curves[0]; 4436 } else { 4437 auth->curve = dpp_get_curve_name(curve); 4438 if (!auth->curve) { 4439 wpa_printf(MSG_INFO, "DPP: Unsupported curve: %s", 4440 curve); 4441 return -1; 4442 } 4443 } 4444 wpa_printf(MSG_DEBUG, 4445 "DPP: Building own configuration/connector with curve %s", 4446 auth->curve->name); 4447 4448 auth->own_protocol_key = dpp_gen_keypair(auth->curve); 4449 if (!auth->own_protocol_key) 4450 return -1; 4451 dpp_copy_netaccesskey(auth); 4452 auth->peer_protocol_key = auth->own_protocol_key; 4453 dpp_copy_csign(auth, auth->conf->csign); 4454 4455 conf_obj = dpp_build_conf_obj(auth, 0); 4456 if (!conf_obj) 4457 goto fail; 4458 ret = dpp_parse_conf_obj(auth, wpabuf_head(conf_obj), 4459 wpabuf_len(conf_obj)); 4460 fail: 4461 wpabuf_free(conf_obj); 4462 auth->peer_protocol_key = NULL; 4463 return ret; 4464 } 4465 4466 4467 static int dpp_compatible_netrole(const char *role1, const char *role2) 4468 { 4469 return (os_strcmp(role1, "sta") == 0 && os_strcmp(role2, "ap") == 0) || 4470 (os_strcmp(role1, "ap") == 0 && os_strcmp(role2, "sta") == 0); 4471 } 4472 4473 4474 static int dpp_connector_compatible_group(struct json_token *root, 4475 const char *group_id, 4476 const char *net_role) 4477 { 4478 struct json_token *groups, *token; 4479 4480 groups = json_get_member(root, "groups"); 4481 if (!groups || groups->type != JSON_ARRAY) 4482 return 0; 4483 4484 for (token = groups->child; token; token = token->sibling) { 4485 struct json_token *id, *role; 4486 4487 id = json_get_member(token, "groupId"); 4488 if (!id || id->type != JSON_STRING) 4489 continue; 4490 4491 role = json_get_member(token, "netRole"); 4492 if (!role || role->type != JSON_STRING) 4493 continue; 4494 4495 if (os_strcmp(id->string, "*") != 0 && 4496 os_strcmp(group_id, "*") != 0 && 4497 os_strcmp(id->string, group_id) != 0) 4498 continue; 4499 4500 if (dpp_compatible_netrole(role->string, net_role)) 4501 return 1; 4502 } 4503 4504 return 0; 4505 } 4506 4507 4508 static int dpp_connector_match_groups(struct json_token *own_root, 4509 struct json_token *peer_root) 4510 { 4511 struct json_token *groups, *token; 4512 4513 groups = json_get_member(peer_root, "groups"); 4514 if (!groups || groups->type != JSON_ARRAY) { 4515 wpa_printf(MSG_DEBUG, "DPP: No peer groups array found"); 4516 return 0; 4517 } 4518 4519 for (token = groups->child; token; token = token->sibling) { 4520 struct json_token *id, *role; 4521 4522 id = json_get_member(token, "groupId"); 4523 if (!id || id->type != JSON_STRING) { 4524 wpa_printf(MSG_DEBUG, 4525 "DPP: Missing peer groupId string"); 4526 continue; 4527 } 4528 4529 role = json_get_member(token, "netRole"); 4530 if (!role || role->type != JSON_STRING) { 4531 wpa_printf(MSG_DEBUG, 4532 "DPP: Missing peer groups::netRole string"); 4533 continue; 4534 } 4535 wpa_printf(MSG_DEBUG, 4536 "DPP: peer connector group: groupId='%s' netRole='%s'", 4537 id->string, role->string); 4538 if (dpp_connector_compatible_group(own_root, id->string, 4539 role->string)) { 4540 wpa_printf(MSG_DEBUG, 4541 "DPP: Compatible group/netRole in own connector"); 4542 return 1; 4543 } 4544 } 4545 4546 return 0; 4547 } 4548 4549 4550 static int dpp_derive_pmk(const u8 *Nx, size_t Nx_len, u8 *pmk, 4551 unsigned int hash_len) 4552 { 4553 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN]; 4554 const char *info = "DPP PMK"; 4555 int res; 4556 4557 /* PMK = HKDF(<>, "DPP PMK", N.x) */ 4558 4559 /* HKDF-Extract(<>, N.x) */ 4560 os_memset(salt, 0, hash_len); 4561 if (dpp_hmac(hash_len, salt, hash_len, Nx, Nx_len, prk) < 0) 4562 return -1; 4563 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM=N.x)", 4564 prk, hash_len); 4565 4566 /* HKDF-Expand(PRK, info, L) */ 4567 res = dpp_hkdf_expand(hash_len, prk, hash_len, info, pmk, hash_len); 4568 os_memset(prk, 0, hash_len); 4569 if (res < 0) 4570 return -1; 4571 4572 wpa_hexdump_key(MSG_DEBUG, "DPP: PMK = HKDF-Expand(PRK, info, L)", 4573 pmk, hash_len); 4574 return 0; 4575 } 4576 4577 4578 static int dpp_derive_pmkid(const struct dpp_curve_params *curve, 4579 EVP_PKEY *own_key, EVP_PKEY *peer_key, u8 *pmkid) 4580 { 4581 struct wpabuf *nkx, *pkx; 4582 int ret = -1, res; 4583 const u8 *addr[2]; 4584 size_t len[2]; 4585 u8 hash[SHA256_MAC_LEN]; 4586 4587 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */ 4588 nkx = dpp_get_pubkey_point(own_key, 0); 4589 pkx = dpp_get_pubkey_point(peer_key, 0); 4590 if (!nkx || !pkx) 4591 goto fail; 4592 addr[0] = wpabuf_head(nkx); 4593 len[0] = wpabuf_len(nkx) / 2; 4594 addr[1] = wpabuf_head(pkx); 4595 len[1] = wpabuf_len(pkx) / 2; 4596 if (len[0] != len[1]) 4597 goto fail; 4598 if (os_memcmp(addr[0], addr[1], len[0]) > 0) { 4599 addr[0] = wpabuf_head(pkx); 4600 addr[1] = wpabuf_head(nkx); 4601 } 4602 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 1", addr[0], len[0]); 4603 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash payload 2", addr[1], len[1]); 4604 res = sha256_vector(2, addr, len, hash); 4605 if (res < 0) 4606 goto fail; 4607 wpa_hexdump(MSG_DEBUG, "DPP: PMKID hash output", hash, SHA256_MAC_LEN); 4608 os_memcpy(pmkid, hash, PMKID_LEN); 4609 wpa_hexdump(MSG_DEBUG, "DPP: PMKID", pmkid, PMKID_LEN); 4610 ret = 0; 4611 fail: 4612 wpabuf_free(nkx); 4613 wpabuf_free(pkx); 4614 return ret; 4615 } 4616 4617 4618 int dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector, 4619 const u8 *net_access_key, size_t net_access_key_len, 4620 const u8 *csign_key, size_t csign_key_len, 4621 const u8 *peer_connector, size_t peer_connector_len, 4622 os_time_t *expiry) 4623 { 4624 struct json_token *root = NULL, *netkey, *token; 4625 struct json_token *own_root = NULL; 4626 int ret = -1; 4627 EVP_PKEY *own_key = NULL, *peer_key = NULL; 4628 struct wpabuf *own_key_pub = NULL; 4629 const struct dpp_curve_params *curve, *own_curve; 4630 struct dpp_signed_connector_info info; 4631 const unsigned char *p; 4632 EVP_PKEY *csign = NULL; 4633 char *signed_connector = NULL; 4634 const char *pos, *end; 4635 unsigned char *own_conn = NULL; 4636 size_t own_conn_len; 4637 EVP_PKEY_CTX *ctx = NULL; 4638 size_t Nx_len; 4639 u8 Nx[DPP_MAX_SHARED_SECRET_LEN]; 4640 4641 os_memset(intro, 0, sizeof(*intro)); 4642 os_memset(&info, 0, sizeof(info)); 4643 if (expiry) 4644 *expiry = 0; 4645 4646 p = csign_key; 4647 csign = d2i_PUBKEY(NULL, &p, csign_key_len); 4648 if (!csign) { 4649 wpa_printf(MSG_ERROR, 4650 "DPP: Failed to parse local C-sign-key information"); 4651 goto fail; 4652 } 4653 4654 own_key = dpp_set_keypair(&own_curve, net_access_key, 4655 net_access_key_len); 4656 if (!own_key) { 4657 wpa_printf(MSG_ERROR, "DPP: Failed to parse own netAccessKey"); 4658 goto fail; 4659 } 4660 4661 pos = os_strchr(own_connector, '.'); 4662 if (!pos) { 4663 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the first dot (.)"); 4664 goto fail; 4665 } 4666 pos++; 4667 end = os_strchr(pos, '.'); 4668 if (!end) { 4669 wpa_printf(MSG_DEBUG, "DPP: Own connector is missing the second dot (.)"); 4670 goto fail; 4671 } 4672 own_conn = base64_url_decode((const unsigned char *) pos, 4673 end - pos, &own_conn_len); 4674 if (!own_conn) { 4675 wpa_printf(MSG_DEBUG, 4676 "DPP: Failed to base64url decode own signedConnector JWS Payload"); 4677 goto fail; 4678 } 4679 4680 own_root = json_parse((const char *) own_conn, own_conn_len); 4681 if (!own_root) { 4682 wpa_printf(MSG_DEBUG, "DPP: Failed to parse local connector"); 4683 goto fail; 4684 } 4685 4686 wpa_hexdump_ascii(MSG_DEBUG, "DPP: Peer signedConnector", 4687 peer_connector, peer_connector_len); 4688 signed_connector = os_malloc(peer_connector_len + 1); 4689 if (!signed_connector) 4690 goto fail; 4691 os_memcpy(signed_connector, peer_connector, peer_connector_len); 4692 signed_connector[peer_connector_len] = '\0'; 4693 4694 if (dpp_process_signed_connector(&info, csign, signed_connector) < 0) 4695 goto fail; 4696 4697 root = json_parse((const char *) info.payload, info.payload_len); 4698 if (!root) { 4699 wpa_printf(MSG_DEBUG, "DPP: JSON parsing of connector failed"); 4700 goto fail; 4701 } 4702 4703 if (!dpp_connector_match_groups(own_root, root)) { 4704 wpa_printf(MSG_DEBUG, 4705 "DPP: Peer connector does not include compatible group netrole with own connector"); 4706 goto fail; 4707 } 4708 4709 token = json_get_member(root, "expiry"); 4710 if (!token || token->type != JSON_STRING) { 4711 wpa_printf(MSG_DEBUG, 4712 "DPP: No expiry string found - connector does not expire"); 4713 } else { 4714 wpa_printf(MSG_DEBUG, "DPP: expiry = %s", token->string); 4715 if (dpp_key_expired(token->string, expiry)) { 4716 wpa_printf(MSG_DEBUG, 4717 "DPP: Connector (netAccessKey) has expired"); 4718 goto fail; 4719 } 4720 } 4721 4722 netkey = json_get_member(root, "netAccessKey"); 4723 if (!netkey || netkey->type != JSON_OBJECT) { 4724 wpa_printf(MSG_DEBUG, "DPP: No netAccessKey object found"); 4725 goto fail; 4726 } 4727 4728 peer_key = dpp_parse_jwk(netkey, &curve); 4729 if (!peer_key) 4730 goto fail; 4731 dpp_debug_print_key("DPP: Received netAccessKey", peer_key); 4732 4733 if (own_curve != curve) { 4734 wpa_printf(MSG_DEBUG, 4735 "DPP: Mismatching netAccessKey curves (%s != %s)", 4736 own_curve->name, curve->name); 4737 goto fail; 4738 } 4739 4740 /* ECDH: N = nk * PK */ 4741 ctx = EVP_PKEY_CTX_new(own_key, NULL); 4742 if (!ctx || 4743 EVP_PKEY_derive_init(ctx) != 1 || 4744 EVP_PKEY_derive_set_peer(ctx, peer_key) != 1 || 4745 EVP_PKEY_derive(ctx, NULL, &Nx_len) != 1 || 4746 Nx_len > DPP_MAX_SHARED_SECRET_LEN || 4747 EVP_PKEY_derive(ctx, Nx, &Nx_len) != 1) { 4748 wpa_printf(MSG_ERROR, 4749 "DPP: Failed to derive ECDH shared secret: %s", 4750 ERR_error_string(ERR_get_error(), NULL)); 4751 goto fail; 4752 } 4753 4754 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (N.x)", 4755 Nx, Nx_len); 4756 4757 /* PMK = HKDF(<>, "DPP PMK", N.x) */ 4758 if (dpp_derive_pmk(Nx, Nx_len, intro->pmk, curve->hash_len) < 0) { 4759 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMK"); 4760 goto fail; 4761 } 4762 intro->pmk_len = curve->hash_len; 4763 4764 /* PMKID = Truncate-128(H(min(NK.x, PK.x) | max(NK.x, PK.x))) */ 4765 if (dpp_derive_pmkid(curve, own_key, peer_key, intro->pmkid) < 0) { 4766 wpa_printf(MSG_ERROR, "DPP: Failed to derive PMKID"); 4767 goto fail; 4768 } 4769 4770 ret = 0; 4771 fail: 4772 if (ret < 0) 4773 os_memset(intro, 0, sizeof(*intro)); 4774 os_memset(Nx, 0, sizeof(Nx)); 4775 EVP_PKEY_CTX_free(ctx); 4776 os_free(own_conn); 4777 os_free(signed_connector); 4778 os_free(info.payload); 4779 EVP_PKEY_free(own_key); 4780 wpabuf_free(own_key_pub); 4781 EVP_PKEY_free(peer_key); 4782 EVP_PKEY_free(csign); 4783 json_free(root); 4784 json_free(own_root); 4785 return ret; 4786 } 4787 4788 4789 static EVP_PKEY * dpp_pkex_get_role_elem(const struct dpp_curve_params *curve, 4790 int init) 4791 { 4792 EC_GROUP *group; 4793 size_t len = curve->prime_len; 4794 const u8 *x, *y; 4795 4796 switch (curve->ike_group) { 4797 case 19: 4798 x = init ? pkex_init_x_p256 : pkex_resp_x_p256; 4799 y = init ? pkex_init_y_p256 : pkex_resp_y_p256; 4800 break; 4801 case 20: 4802 x = init ? pkex_init_x_p384 : pkex_resp_x_p384; 4803 y = init ? pkex_init_y_p384 : pkex_resp_y_p384; 4804 break; 4805 case 21: 4806 x = init ? pkex_init_x_p521 : pkex_resp_x_p521; 4807 y = init ? pkex_init_y_p521 : pkex_resp_y_p521; 4808 break; 4809 case 28: 4810 x = init ? pkex_init_x_bp_p256r1 : pkex_resp_x_bp_p256r1; 4811 y = init ? pkex_init_y_bp_p256r1 : pkex_resp_y_bp_p256r1; 4812 break; 4813 case 29: 4814 x = init ? pkex_init_x_bp_p384r1 : pkex_resp_x_bp_p384r1; 4815 y = init ? pkex_init_y_bp_p384r1 : pkex_resp_y_bp_p384r1; 4816 break; 4817 case 30: 4818 x = init ? pkex_init_x_bp_p512r1 : pkex_resp_x_bp_p512r1; 4819 y = init ? pkex_init_y_bp_p512r1 : pkex_resp_y_bp_p512r1; 4820 break; 4821 default: 4822 return NULL; 4823 } 4824 4825 group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(curve->name)); 4826 if (!group) 4827 return NULL; 4828 return dpp_set_pubkey_point_group(group, x, y, len); 4829 } 4830 4831 4832 static EC_POINT * dpp_pkex_derive_Qi(const struct dpp_curve_params *curve, 4833 const u8 *mac_init, const char *code, 4834 const char *identifier, BN_CTX *bnctx, 4835 const EC_GROUP **ret_group) 4836 { 4837 u8 hash[DPP_MAX_HASH_LEN]; 4838 const u8 *addr[3]; 4839 size_t len[3]; 4840 unsigned int num_elem = 0; 4841 EC_POINT *Qi = NULL; 4842 EVP_PKEY *Pi = NULL; 4843 EC_KEY *Pi_ec = NULL; 4844 const EC_POINT *Pi_point; 4845 BIGNUM *hash_bn = NULL; 4846 const EC_GROUP *group = NULL; 4847 EC_GROUP *group2 = NULL; 4848 4849 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */ 4850 4851 wpa_printf(MSG_DEBUG, "DPP: MAC-Initiator: " MACSTR, MAC2STR(mac_init)); 4852 addr[num_elem] = mac_init; 4853 len[num_elem] = ETH_ALEN; 4854 num_elem++; 4855 if (identifier) { 4856 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s", 4857 identifier); 4858 addr[num_elem] = (const u8 *) identifier; 4859 len[num_elem] = os_strlen(identifier); 4860 num_elem++; 4861 } 4862 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code)); 4863 addr[num_elem] = (const u8 *) code; 4864 len[num_elem] = os_strlen(code); 4865 num_elem++; 4866 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0) 4867 goto fail; 4868 wpa_hexdump_key(MSG_DEBUG, 4869 "DPP: H(MAC-Initiator | [identifier |] code)", 4870 hash, curve->hash_len); 4871 Pi = dpp_pkex_get_role_elem(curve, 1); 4872 if (!Pi) 4873 goto fail; 4874 dpp_debug_print_key("DPP: Pi", Pi); 4875 Pi_ec = EVP_PKEY_get1_EC_KEY(Pi); 4876 if (!Pi_ec) 4877 goto fail; 4878 Pi_point = EC_KEY_get0_public_key(Pi_ec); 4879 4880 group = EC_KEY_get0_group(Pi_ec); 4881 if (!group) 4882 goto fail; 4883 group2 = EC_GROUP_dup(group); 4884 if (!group2) 4885 goto fail; 4886 Qi = EC_POINT_new(group2); 4887 if (!Qi) { 4888 EC_GROUP_free(group2); 4889 goto fail; 4890 } 4891 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL); 4892 if (!hash_bn || 4893 EC_POINT_mul(group2, Qi, NULL, Pi_point, hash_bn, bnctx) != 1) 4894 goto fail; 4895 if (EC_POINT_is_at_infinity(group, Qi)) { 4896 wpa_printf(MSG_INFO, "PDP: Qi is the point-at-infinity"); 4897 goto fail; 4898 } 4899 out: 4900 EC_KEY_free(Pi_ec); 4901 EVP_PKEY_free(Pi); 4902 BN_clear_free(hash_bn); 4903 if (ret_group) 4904 *ret_group = group2; 4905 return Qi; 4906 fail: 4907 EC_POINT_free(Qi); 4908 Qi = NULL; 4909 goto out; 4910 } 4911 4912 4913 static EC_POINT * dpp_pkex_derive_Qr(const struct dpp_curve_params *curve, 4914 const u8 *mac_resp, const char *code, 4915 const char *identifier, BN_CTX *bnctx, 4916 const EC_GROUP **ret_group) 4917 { 4918 u8 hash[DPP_MAX_HASH_LEN]; 4919 const u8 *addr[3]; 4920 size_t len[3]; 4921 unsigned int num_elem = 0; 4922 EC_POINT *Qr = NULL; 4923 EVP_PKEY *Pr = NULL; 4924 EC_KEY *Pr_ec = NULL; 4925 const EC_POINT *Pr_point; 4926 BIGNUM *hash_bn = NULL; 4927 const EC_GROUP *group = NULL; 4928 EC_GROUP *group2 = NULL; 4929 4930 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */ 4931 4932 wpa_printf(MSG_DEBUG, "DPP: MAC-Responder: " MACSTR, MAC2STR(mac_resp)); 4933 addr[num_elem] = mac_resp; 4934 len[num_elem] = ETH_ALEN; 4935 num_elem++; 4936 if (identifier) { 4937 wpa_printf(MSG_DEBUG, "DPP: code identifier: %s", 4938 identifier); 4939 addr[num_elem] = (const u8 *) identifier; 4940 len[num_elem] = os_strlen(identifier); 4941 num_elem++; 4942 } 4943 wpa_hexdump_ascii_key(MSG_DEBUG, "DPP: code", code, os_strlen(code)); 4944 addr[num_elem] = (const u8 *) code; 4945 len[num_elem] = os_strlen(code); 4946 num_elem++; 4947 if (dpp_hash_vector(curve, num_elem, addr, len, hash) < 0) 4948 goto fail; 4949 wpa_hexdump_key(MSG_DEBUG, 4950 "DPP: H(MAC-Responder | [identifier |] code)", 4951 hash, curve->hash_len); 4952 Pr = dpp_pkex_get_role_elem(curve, 0); 4953 if (!Pr) 4954 goto fail; 4955 dpp_debug_print_key("DPP: Pr", Pr); 4956 Pr_ec = EVP_PKEY_get1_EC_KEY(Pr); 4957 if (!Pr_ec) 4958 goto fail; 4959 Pr_point = EC_KEY_get0_public_key(Pr_ec); 4960 4961 group = EC_KEY_get0_group(Pr_ec); 4962 if (!group) 4963 goto fail; 4964 group2 = EC_GROUP_dup(group); 4965 if (!group2) 4966 goto fail; 4967 Qr = EC_POINT_new(group2); 4968 if (!Qr) { 4969 EC_GROUP_free(group2); 4970 goto fail; 4971 } 4972 hash_bn = BN_bin2bn(hash, curve->hash_len, NULL); 4973 if (!hash_bn || 4974 EC_POINT_mul(group2, Qr, NULL, Pr_point, hash_bn, bnctx) != 1) 4975 goto fail; 4976 out: 4977 EC_KEY_free(Pr_ec); 4978 EVP_PKEY_free(Pr); 4979 BN_clear_free(hash_bn); 4980 if (ret_group) 4981 *ret_group = group2; 4982 return Qr; 4983 fail: 4984 EC_POINT_free(Qr); 4985 Qr = NULL; 4986 goto out; 4987 } 4988 4989 4990 static struct wpabuf * dpp_pkex_build_exchange_req(struct dpp_pkex *pkex) 4991 { 4992 EC_KEY *X_ec = NULL; 4993 const EC_POINT *X_point; 4994 BN_CTX *bnctx = NULL; 4995 const EC_GROUP *group; 4996 EC_POINT *Qi = NULL, *M = NULL; 4997 struct wpabuf *M_buf = NULL; 4998 BIGNUM *Mx = NULL, *My = NULL; 4999 struct wpabuf *msg = NULL; 5000 size_t attr_len; 5001 const struct dpp_curve_params *curve = pkex->own_bi->curve; 5002 int num_bytes, offset; 5003 5004 wpa_printf(MSG_DEBUG, "DPP: Build PKEX Exchange Request"); 5005 5006 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */ 5007 bnctx = BN_CTX_new(); 5008 if (!bnctx) 5009 goto fail; 5010 Qi = dpp_pkex_derive_Qi(curve, pkex->own_mac, pkex->code, 5011 pkex->identifier, bnctx, &group); 5012 if (!Qi) 5013 goto fail; 5014 5015 /* Generate a random ephemeral keypair x/X */ 5016 pkex->x = dpp_gen_keypair(curve); 5017 if (!pkex->x) 5018 goto fail; 5019 5020 /* M = X + Qi */ 5021 X_ec = EVP_PKEY_get1_EC_KEY(pkex->x); 5022 if (!X_ec) 5023 goto fail; 5024 X_point = EC_KEY_get0_public_key(X_ec); 5025 if (!X_point) 5026 goto fail; 5027 M = EC_POINT_new(group); 5028 Mx = BN_new(); 5029 My = BN_new(); 5030 if (!M || !Mx || !My || 5031 EC_POINT_add(group, M, X_point, Qi, bnctx) != 1 || 5032 EC_POINT_get_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1) 5033 goto fail; 5034 5035 /* Initiator -> Responder: group, [identifier,] M */ 5036 attr_len = 4 + 2; 5037 if (pkex->identifier) 5038 attr_len += 4 + os_strlen(pkex->identifier); 5039 attr_len += 4 + 2 * curve->prime_len; 5040 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_REQ, attr_len); 5041 if (!msg) 5042 goto fail; 5043 5044 /* Finite Cyclic Group attribute */ 5045 wpabuf_put_le16(msg, DPP_ATTR_FINITE_CYCLIC_GROUP); 5046 wpabuf_put_le16(msg, 2); 5047 wpabuf_put_le16(msg, curve->ike_group); 5048 5049 /* Code Identifier attribute */ 5050 if (pkex->identifier) { 5051 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER); 5052 wpabuf_put_le16(msg, os_strlen(pkex->identifier)); 5053 wpabuf_put_str(msg, pkex->identifier); 5054 } 5055 5056 /* M in Encrypted Key attribute */ 5057 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY); 5058 wpabuf_put_le16(msg, 2 * curve->prime_len); 5059 5060 num_bytes = BN_num_bytes(Mx); 5061 if ((size_t) num_bytes > curve->prime_len) 5062 goto fail; 5063 if (curve->prime_len > (size_t) num_bytes) 5064 offset = curve->prime_len - num_bytes; 5065 else 5066 offset = 0; 5067 os_memset(wpabuf_put(msg, offset), 0, offset); 5068 BN_bn2bin(Mx, wpabuf_put(msg, num_bytes)); 5069 os_memset(pkex->Mx, 0, offset); 5070 BN_bn2bin(Mx, pkex->Mx + offset); 5071 5072 num_bytes = BN_num_bytes(My); 5073 if ((size_t) num_bytes > curve->prime_len) 5074 goto fail; 5075 if (curve->prime_len > (size_t) num_bytes) 5076 offset = curve->prime_len - num_bytes; 5077 else 5078 offset = 0; 5079 os_memset(wpabuf_put(msg, offset), 0, offset); 5080 BN_bn2bin(My, wpabuf_put(msg, num_bytes)); 5081 5082 out: 5083 wpabuf_free(M_buf); 5084 EC_KEY_free(X_ec); 5085 EC_POINT_free(M); 5086 EC_POINT_free(Qi); 5087 BN_clear_free(Mx); 5088 BN_clear_free(My); 5089 BN_CTX_free(bnctx); 5090 return msg; 5091 fail: 5092 wpa_printf(MSG_INFO, "DPP: Failed to build PKEX Exchange Request"); 5093 wpabuf_free(msg); 5094 msg = NULL; 5095 goto out; 5096 } 5097 5098 5099 struct dpp_pkex * dpp_pkex_init(struct dpp_bootstrap_info *bi, 5100 const u8 *own_mac, 5101 const char *identifier, 5102 const char *code) 5103 { 5104 struct dpp_pkex *pkex; 5105 5106 pkex = os_zalloc(sizeof(*pkex)); 5107 if (!pkex) 5108 return NULL; 5109 pkex->initiator = 1; 5110 pkex->own_bi = bi; 5111 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN); 5112 if (identifier) { 5113 pkex->identifier = os_strdup(identifier); 5114 if (!pkex->identifier) 5115 goto fail; 5116 } 5117 pkex->code = os_strdup(code); 5118 if (!pkex->code) 5119 goto fail; 5120 pkex->exchange_req = dpp_pkex_build_exchange_req(pkex); 5121 if (!pkex->exchange_req) 5122 goto fail; 5123 return pkex; 5124 fail: 5125 dpp_pkex_free(pkex); 5126 return NULL; 5127 } 5128 5129 5130 struct dpp_pkex * dpp_pkex_rx_exchange_req(struct dpp_bootstrap_info *bi, 5131 const u8 *own_mac, 5132 const u8 *peer_mac, 5133 const char *identifier, 5134 const char *code, 5135 const u8 *buf, size_t len) 5136 { 5137 const u8 *attr_group, *attr_id, *attr_key; 5138 u16 attr_group_len, attr_id_len, attr_key_len; 5139 const struct dpp_curve_params *curve = bi->curve; 5140 u16 ike_group; 5141 struct dpp_pkex *pkex = NULL; 5142 EC_POINT *Qi = NULL, *Qr = NULL, *M = NULL, *X = NULL, *N = NULL; 5143 BN_CTX *bnctx = NULL; 5144 const EC_GROUP *group; 5145 BIGNUM *Mx = NULL, *My = NULL; 5146 EC_KEY *Y_ec = NULL, *X_ec = NULL;; 5147 const EC_POINT *Y_point; 5148 BIGNUM *Nx = NULL, *Ny = NULL; 5149 struct wpabuf *msg = NULL; 5150 size_t attr_len; 5151 int num_bytes, offset; 5152 5153 attr_id = dpp_get_attr(buf, len, DPP_ATTR_CODE_IDENTIFIER, 5154 &attr_id_len); 5155 if (!attr_id && identifier) { 5156 wpa_printf(MSG_DEBUG, 5157 "DPP: No PKEX code identifier received, but expected one"); 5158 return NULL; 5159 } 5160 if (attr_id && identifier && 5161 (os_strlen(identifier) != attr_id_len || 5162 os_memcmp(identifier, attr_id, attr_id_len) != 0)) { 5163 wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch"); 5164 return NULL; 5165 } 5166 5167 attr_group = dpp_get_attr(buf, len, DPP_ATTR_FINITE_CYCLIC_GROUP, 5168 &attr_group_len); 5169 if (!attr_group || attr_group_len != 2) { 5170 wpa_printf(MSG_DEBUG, 5171 "DPP: Missing or invalid Finite Cyclic Group attribute"); 5172 return NULL; 5173 } 5174 ike_group = WPA_GET_LE16(attr_group); 5175 if (ike_group != curve->ike_group) { 5176 wpa_printf(MSG_DEBUG, 5177 "DPP: Mismatching PKEX curve: peer=%u own=%u", 5178 ike_group, curve->ike_group); 5179 /* TODO: error response with suggested curve: 5180 * DPP Status, group */ 5181 return NULL; 5182 } 5183 5184 /* M in Encrypted Key attribute */ 5185 attr_key = dpp_get_attr(buf, len, DPP_ATTR_ENCRYPTED_KEY, 5186 &attr_key_len); 5187 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2 || 5188 attr_key_len / 2 > DPP_MAX_SHARED_SECRET_LEN) { 5189 wpa_printf(MSG_DEBUG, "DPP: Missing Encrypted Key attribute"); 5190 return NULL; 5191 } 5192 5193 /* Qi = H(MAC-Initiator | [identifier |] code) * Pi */ 5194 bnctx = BN_CTX_new(); 5195 if (!bnctx) 5196 goto fail; 5197 Qi = dpp_pkex_derive_Qi(curve, peer_mac, code, identifier, bnctx, 5198 &group); 5199 if (!Qi) 5200 goto fail; 5201 5202 /* X' = M - Qi */ 5203 X = EC_POINT_new(group); 5204 M = EC_POINT_new(group); 5205 Mx = BN_bin2bn(attr_key, attr_key_len / 2, NULL); 5206 My = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL); 5207 if (!X || !M || !Mx || !My || 5208 EC_POINT_set_affine_coordinates_GFp(group, M, Mx, My, bnctx) != 1 || 5209 EC_POINT_is_at_infinity(group, M) || 5210 !EC_POINT_is_on_curve(group, M, bnctx) || 5211 EC_POINT_invert(group, Qi, bnctx) != 1 || 5212 EC_POINT_add(group, X, M, Qi, bnctx) != 1 || 5213 EC_POINT_is_at_infinity(group, X) || 5214 !EC_POINT_is_on_curve(group, X, bnctx)) 5215 goto fail; 5216 5217 pkex = os_zalloc(sizeof(*pkex)); 5218 if (!pkex) 5219 goto fail; 5220 pkex->own_bi = bi; 5221 os_memcpy(pkex->own_mac, own_mac, ETH_ALEN); 5222 os_memcpy(pkex->peer_mac, peer_mac, ETH_ALEN); 5223 if (identifier) { 5224 pkex->identifier = os_strdup(identifier); 5225 if (!pkex->identifier) 5226 goto fail; 5227 } 5228 pkex->code = os_strdup(code); 5229 if (!pkex->code) 5230 goto fail; 5231 5232 os_memcpy(pkex->Mx, attr_key, attr_key_len / 2); 5233 5234 X_ec = EC_KEY_new(); 5235 if (!X_ec || 5236 EC_KEY_set_group(X_ec, group) != 1 || 5237 EC_KEY_set_public_key(X_ec, X) != 1) 5238 goto fail; 5239 pkex->x = EVP_PKEY_new(); 5240 if (!pkex->x || 5241 EVP_PKEY_set1_EC_KEY(pkex->x, X_ec) != 1) 5242 goto fail; 5243 5244 /* Qr = H(MAC-Responder | | [identifier | ] code) * Pr */ 5245 Qr = dpp_pkex_derive_Qr(curve, own_mac, code, identifier, bnctx, NULL); 5246 if (!Qr) 5247 goto fail; 5248 5249 /* Generate a random ephemeral keypair y/Y */ 5250 pkex->y = dpp_gen_keypair(curve); 5251 if (!pkex->y) 5252 goto fail; 5253 5254 /* N = Y + Qr */ 5255 Y_ec = EVP_PKEY_get1_EC_KEY(pkex->y); 5256 if (!Y_ec) 5257 goto fail; 5258 Y_point = EC_KEY_get0_public_key(Y_ec); 5259 if (!Y_point) 5260 goto fail; 5261 N = EC_POINT_new(group); 5262 Nx = BN_new(); 5263 Ny = BN_new(); 5264 if (!N || !Nx || !Ny || 5265 EC_POINT_add(group, N, Y_point, Qr, bnctx) != 1 || 5266 EC_POINT_get_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1) 5267 goto fail; 5268 5269 /* Initiator -> Responder: DPP Status, [identifier,] N */ 5270 attr_len = 4 + 1; 5271 if (identifier) 5272 attr_len += 4 + os_strlen(identifier); 5273 attr_len += 4 + 2 * curve->prime_len; 5274 msg = dpp_alloc_msg(DPP_PA_PKEX_EXCHANGE_RESP, attr_len); 5275 if (!msg) 5276 goto fail; 5277 5278 /* DPP Status */ 5279 wpabuf_put_le16(msg, DPP_ATTR_STATUS); 5280 wpabuf_put_le16(msg, 1); 5281 wpabuf_put_u8(msg, DPP_STATUS_OK); 5282 5283 /* Code Identifier attribute */ 5284 if (pkex->identifier) { 5285 wpabuf_put_le16(msg, DPP_ATTR_CODE_IDENTIFIER); 5286 wpabuf_put_le16(msg, os_strlen(pkex->identifier)); 5287 wpabuf_put_str(msg, pkex->identifier); 5288 } 5289 5290 /* N in Encrypted Key attribute */ 5291 wpabuf_put_le16(msg, DPP_ATTR_ENCRYPTED_KEY); 5292 wpabuf_put_le16(msg, 2 * curve->prime_len); 5293 5294 num_bytes = BN_num_bytes(Nx); 5295 if ((size_t) num_bytes > curve->prime_len) 5296 goto fail; 5297 if (curve->prime_len > (size_t) num_bytes) 5298 offset = curve->prime_len - num_bytes; 5299 else 5300 offset = 0; 5301 os_memset(wpabuf_put(msg, offset), 0, offset); 5302 BN_bn2bin(Nx, wpabuf_put(msg, num_bytes)); 5303 os_memset(pkex->Nx, 0, offset); 5304 BN_bn2bin(Nx, pkex->Nx + offset); 5305 5306 num_bytes = BN_num_bytes(Ny); 5307 if ((size_t) num_bytes > curve->prime_len) 5308 goto fail; 5309 if (curve->prime_len > (size_t) num_bytes) 5310 offset = curve->prime_len - num_bytes; 5311 else 5312 offset = 0; 5313 os_memset(wpabuf_put(msg, offset), 0, offset); 5314 BN_bn2bin(Ny, wpabuf_put(msg, num_bytes)); 5315 5316 pkex->exchange_resp = msg; 5317 msg = NULL; 5318 pkex->exchange_done = 1; 5319 5320 out: 5321 wpabuf_free(msg); 5322 BN_CTX_free(bnctx); 5323 EC_POINT_free(Qi); 5324 EC_POINT_free(Qr); 5325 BN_free(Mx); 5326 BN_free(My); 5327 BN_free(Nx); 5328 BN_free(Ny); 5329 EC_POINT_free(M); 5330 EC_POINT_free(N); 5331 EC_POINT_free(X); 5332 EC_KEY_free(X_ec); 5333 EC_KEY_free(Y_ec); 5334 return pkex; 5335 fail: 5336 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Request processing faileed"); 5337 dpp_pkex_free(pkex); 5338 pkex = NULL; 5339 goto out; 5340 } 5341 5342 5343 static int dpp_pkex_derive_z(const u8 *mac_init, const u8 *mac_resp, 5344 const u8 *Mx, size_t Mx_len, 5345 const u8 *Nx, size_t Nx_len, 5346 const char *code, 5347 const u8 *Kx, size_t Kx_len, 5348 u8 *z, unsigned int hash_len) 5349 { 5350 u8 salt[DPP_MAX_HASH_LEN], prk[DPP_MAX_HASH_LEN]; 5351 int res; 5352 u8 *info, *pos; 5353 size_t info_len; 5354 5355 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x) 5356 */ 5357 5358 /* HKDF-Extract(<>, IKM=K.x) */ 5359 os_memset(salt, 0, hash_len); 5360 if (dpp_hmac(hash_len, salt, hash_len, Kx, Kx_len, prk) < 0) 5361 return -1; 5362 wpa_hexdump_key(MSG_DEBUG, "DPP: PRK = HKDF-Extract(<>, IKM)", 5363 prk, hash_len); 5364 info_len = 2 * ETH_ALEN + Mx_len + Nx_len + os_strlen(code); 5365 info = os_malloc(info_len); 5366 if (!info) 5367 return -1; 5368 pos = info; 5369 os_memcpy(pos, mac_init, ETH_ALEN); 5370 pos += ETH_ALEN; 5371 os_memcpy(pos, mac_resp, ETH_ALEN); 5372 pos += ETH_ALEN; 5373 os_memcpy(pos, Mx, Mx_len); 5374 pos += Mx_len; 5375 os_memcpy(pos, Nx, Nx_len); 5376 pos += Nx_len; 5377 os_memcpy(pos, code, os_strlen(code)); 5378 5379 /* HKDF-Expand(PRK, info, L) */ 5380 if (hash_len == 32) 5381 res = hmac_sha256_kdf(prk, hash_len, NULL, info, info_len, 5382 z, hash_len); 5383 else if (hash_len == 48) 5384 res = hmac_sha384_kdf(prk, hash_len, NULL, info, info_len, 5385 z, hash_len); 5386 else if (hash_len == 64) 5387 res = hmac_sha512_kdf(prk, hash_len, NULL, info, info_len, 5388 z, hash_len); 5389 else 5390 res = -1; 5391 os_free(info); 5392 os_memset(prk, 0, hash_len); 5393 if (res < 0) 5394 return -1; 5395 5396 wpa_hexdump_key(MSG_DEBUG, "DPP: z = HKDF-Expand(PRK, info, L)", 5397 z, hash_len); 5398 return 0; 5399 } 5400 5401 5402 struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex, 5403 const u8 *buf, size_t buflen) 5404 { 5405 const u8 *attr_status, *attr_id, *attr_key; 5406 u16 attr_status_len, attr_id_len, attr_key_len; 5407 const EC_GROUP *group; 5408 BN_CTX *bnctx = NULL; 5409 size_t clear_len; 5410 struct wpabuf *clear = NULL; 5411 u8 *wrapped; 5412 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL; 5413 const struct dpp_curve_params *curve = pkex->own_bi->curve; 5414 EC_POINT *Qr = NULL, *Y = NULL, *N = NULL; 5415 BIGNUM *Nx = NULL, *Ny = NULL; 5416 EVP_PKEY_CTX *ctx = NULL; 5417 EC_KEY *Y_ec = NULL; 5418 size_t Jx_len, Kx_len; 5419 u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN]; 5420 const u8 *addr[4]; 5421 size_t len[4]; 5422 u8 u[DPP_MAX_HASH_LEN]; 5423 u8 octet; 5424 int res; 5425 5426 attr_status = dpp_get_attr(buf, buflen, DPP_ATTR_STATUS, 5427 &attr_status_len); 5428 if (!attr_status || attr_status_len != 1) { 5429 wpa_printf(MSG_DEBUG, "DPP: No DPP Status attribute"); 5430 return NULL; 5431 } 5432 wpa_printf(MSG_DEBUG, "DPP: Status %u", attr_status[0]); 5433 if (attr_status[0] != DPP_STATUS_OK) { 5434 wpa_printf(MSG_DEBUG, "DPP: PKEX failed"); 5435 return NULL; 5436 } 5437 5438 attr_id = dpp_get_attr(buf, buflen, DPP_ATTR_CODE_IDENTIFIER, 5439 &attr_id_len); 5440 if (!attr_id && pkex->identifier) { 5441 wpa_printf(MSG_DEBUG, 5442 "DPP: No PKEX code identifier received, but expected one"); 5443 return NULL; 5444 } 5445 if (attr_id && pkex->identifier && 5446 (os_strlen(pkex->identifier) != attr_id_len || 5447 os_memcmp(pkex->identifier, attr_id, attr_id_len) != 0)) { 5448 wpa_printf(MSG_DEBUG, "DPP: PKEX code identifier mismatch"); 5449 return NULL; 5450 } 5451 5452 /* N in Encrypted Key attribute */ 5453 attr_key = dpp_get_attr(buf, buflen, DPP_ATTR_ENCRYPTED_KEY, 5454 &attr_key_len); 5455 if (!attr_key || attr_key_len & 0x01 || attr_key_len < 2) { 5456 wpa_printf(MSG_DEBUG, "DPP: Missing Encrypted Key attribute"); 5457 return NULL; 5458 } 5459 5460 /* Qr = H(MAC-Responder | [identifier |] code) * Pr */ 5461 bnctx = BN_CTX_new(); 5462 if (!bnctx) 5463 goto fail; 5464 Qr = dpp_pkex_derive_Qr(curve, pkex->peer_mac, pkex->code, 5465 pkex->identifier, bnctx, &group); 5466 if (!Qr) 5467 goto fail; 5468 5469 /* Y' = N - Qr */ 5470 Y = EC_POINT_new(group); 5471 N = EC_POINT_new(group); 5472 Nx = BN_bin2bn(attr_key, attr_key_len / 2, NULL); 5473 Ny = BN_bin2bn(attr_key + attr_key_len / 2, attr_key_len / 2, NULL); 5474 if (!Y || !N || !Nx || !Ny || 5475 EC_POINT_set_affine_coordinates_GFp(group, N, Nx, Ny, bnctx) != 1 || 5476 EC_POINT_is_at_infinity(group, N) || 5477 !EC_POINT_is_on_curve(group, N, bnctx) || 5478 EC_POINT_invert(group, Qr, bnctx) != 1 || 5479 EC_POINT_add(group, Y, N, Qr, bnctx) != 1 || 5480 EC_POINT_is_at_infinity(group, Y) || 5481 !EC_POINT_is_on_curve(group, Y, bnctx)) 5482 goto fail; 5483 5484 pkex->exchange_done = 1; 5485 5486 /* ECDH: J = a * Y */ 5487 Y_ec = EC_KEY_new(); 5488 if (!Y_ec || 5489 EC_KEY_set_group(Y_ec, group) != 1 || 5490 EC_KEY_set_public_key(Y_ec, Y) != 1) 5491 goto fail; 5492 pkex->y = EVP_PKEY_new(); 5493 if (!pkex->y || 5494 EVP_PKEY_set1_EC_KEY(pkex->y, Y_ec) != 1) 5495 goto fail; 5496 ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL); 5497 if (!ctx || 5498 EVP_PKEY_derive_init(ctx) != 1 || 5499 EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 || 5500 EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 || 5501 Jx_len > DPP_MAX_SHARED_SECRET_LEN || 5502 EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) { 5503 wpa_printf(MSG_ERROR, 5504 "DPP: Failed to derive ECDH shared secret: %s", 5505 ERR_error_string(ERR_get_error(), NULL)); 5506 goto fail; 5507 } 5508 5509 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)", 5510 Jx, Jx_len); 5511 5512 /* u = HMAC(J.x, MAC-Initiator | A.x | Y.x | X.x ) */ 5513 A_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0); 5514 Y_pub = dpp_get_pubkey_point(pkex->y, 0); 5515 X_pub = dpp_get_pubkey_point(pkex->x, 0); 5516 if (!A_pub || !Y_pub || !X_pub) 5517 goto fail; 5518 addr[0] = pkex->own_mac; 5519 len[0] = ETH_ALEN; 5520 addr[1] = wpabuf_head(A_pub); 5521 len[1] = wpabuf_len(A_pub) / 2; 5522 addr[2] = wpabuf_head(Y_pub); 5523 len[2] = wpabuf_len(Y_pub) / 2; 5524 addr[3] = wpabuf_head(X_pub); 5525 len[3] = wpabuf_len(X_pub) / 2; 5526 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0) 5527 goto fail; 5528 wpa_hexdump(MSG_DEBUG, "DPP: u", u, curve->hash_len); 5529 5530 /* K = x * Y */ 5531 EVP_PKEY_CTX_free(ctx); 5532 ctx = EVP_PKEY_CTX_new(pkex->x, NULL); 5533 if (!ctx || 5534 EVP_PKEY_derive_init(ctx) != 1 || 5535 EVP_PKEY_derive_set_peer(ctx, pkex->y) != 1 || 5536 EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 || 5537 Kx_len > DPP_MAX_SHARED_SECRET_LEN || 5538 EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) { 5539 wpa_printf(MSG_ERROR, 5540 "DPP: Failed to derive ECDH shared secret: %s", 5541 ERR_error_string(ERR_get_error(), NULL)); 5542 goto fail; 5543 } 5544 5545 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)", 5546 Kx, Kx_len); 5547 5548 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x) 5549 */ 5550 res = dpp_pkex_derive_z(pkex->own_mac, pkex->peer_mac, 5551 pkex->Mx, curve->prime_len, 5552 attr_key /* N.x */, attr_key_len / 2, 5553 pkex->code, Kx, Kx_len, 5554 pkex->z, curve->hash_len); 5555 os_memset(Kx, 0, Kx_len); 5556 if (res < 0) 5557 goto fail; 5558 5559 /* {A, u, [bootstrapping info]}z */ 5560 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len; 5561 clear = wpabuf_alloc(clear_len); 5562 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_REQ, 5563 4 + clear_len + AES_BLOCK_SIZE); 5564 if (!clear || !msg) 5565 goto fail; 5566 5567 /* A in Bootstrap Key attribute */ 5568 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY); 5569 wpabuf_put_le16(clear, wpabuf_len(A_pub)); 5570 wpabuf_put_buf(clear, A_pub); 5571 5572 /* u in I-Auth tag attribute */ 5573 wpabuf_put_le16(clear, DPP_ATTR_I_AUTH_TAG); 5574 wpabuf_put_le16(clear, curve->hash_len); 5575 wpabuf_put_data(clear, u, curve->hash_len); 5576 5577 addr[0] = wpabuf_head_u8(msg) + 2; 5578 len[0] = DPP_HDR_LEN; 5579 octet = 0; 5580 addr[1] = &octet; 5581 len[1] = sizeof(octet); 5582 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 5583 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 5584 5585 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 5586 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 5587 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 5588 5589 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 5590 if (aes_siv_encrypt(pkex->z, curve->hash_len, 5591 wpabuf_head(clear), wpabuf_len(clear), 5592 2, addr, len, wrapped) < 0) 5593 goto fail; 5594 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 5595 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE); 5596 5597 out: 5598 wpabuf_free(clear); 5599 wpabuf_free(A_pub); 5600 wpabuf_free(X_pub); 5601 wpabuf_free(Y_pub); 5602 EC_POINT_free(Qr); 5603 EC_POINT_free(Y); 5604 EC_POINT_free(N); 5605 BN_free(Nx); 5606 BN_free(Ny); 5607 EC_KEY_free(Y_ec); 5608 EVP_PKEY_CTX_free(ctx); 5609 BN_CTX_free(bnctx); 5610 return msg; 5611 fail: 5612 wpa_printf(MSG_DEBUG, "DPP: PKEX Exchange Response processing faileed"); 5613 wpabuf_free(msg); 5614 msg = NULL; 5615 goto out; 5616 } 5617 5618 5619 struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex, 5620 const u8 *hdr, 5621 const u8 *buf, size_t buflen) 5622 { 5623 const struct dpp_curve_params *curve = pkex->own_bi->curve; 5624 EVP_PKEY_CTX *ctx; 5625 size_t Jx_len, Kx_len, Lx_len; 5626 u8 Jx[DPP_MAX_SHARED_SECRET_LEN], Kx[DPP_MAX_SHARED_SECRET_LEN]; 5627 u8 Lx[DPP_MAX_SHARED_SECRET_LEN]; 5628 const u8 *wrapped_data, *b_key, *peer_u; 5629 u16 wrapped_data_len, b_key_len, peer_u_len = 0; 5630 const u8 *addr[4]; 5631 size_t len[4]; 5632 u8 octet; 5633 u8 *unwrapped = NULL; 5634 size_t unwrapped_len = 0; 5635 struct wpabuf *msg = NULL, *A_pub = NULL, *X_pub = NULL, *Y_pub = NULL; 5636 struct wpabuf *B_pub = NULL; 5637 u8 u[DPP_MAX_HASH_LEN], v[DPP_MAX_HASH_LEN]; 5638 size_t clear_len; 5639 struct wpabuf *clear = NULL; 5640 u8 *wrapped; 5641 int res; 5642 5643 /* K = y * X' */ 5644 ctx = EVP_PKEY_CTX_new(pkex->y, NULL); 5645 if (!ctx || 5646 EVP_PKEY_derive_init(ctx) != 1 || 5647 EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 || 5648 EVP_PKEY_derive(ctx, NULL, &Kx_len) != 1 || 5649 Kx_len > DPP_MAX_SHARED_SECRET_LEN || 5650 EVP_PKEY_derive(ctx, Kx, &Kx_len) != 1) { 5651 wpa_printf(MSG_ERROR, 5652 "DPP: Failed to derive ECDH shared secret: %s", 5653 ERR_error_string(ERR_get_error(), NULL)); 5654 goto fail; 5655 } 5656 5657 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (K.x)", 5658 Kx, Kx_len); 5659 5660 /* z = HKDF(<>, MAC-Initiator | MAC-Responder | M.x | N.x | code, K.x) 5661 */ 5662 res = dpp_pkex_derive_z(pkex->peer_mac, pkex->own_mac, 5663 pkex->Mx, curve->prime_len, 5664 pkex->Nx, curve->prime_len, pkex->code, 5665 Kx, Kx_len, pkex->z, curve->hash_len); 5666 os_memset(Kx, 0, Kx_len); 5667 if (res < 0) 5668 goto fail; 5669 5670 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA, 5671 &wrapped_data_len); 5672 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 5673 wpa_printf(MSG_DEBUG, 5674 "DPP: Missing or invalid required Wrapped data attribute"); 5675 goto fail; 5676 } 5677 5678 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 5679 wrapped_data, wrapped_data_len); 5680 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 5681 unwrapped = os_malloc(unwrapped_len); 5682 if (!unwrapped) 5683 goto fail; 5684 5685 addr[0] = hdr; 5686 len[0] = DPP_HDR_LEN; 5687 octet = 0; 5688 addr[1] = &octet; 5689 len[1] = sizeof(octet); 5690 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 5691 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 5692 5693 if (aes_siv_decrypt(pkex->z, curve->hash_len, 5694 wrapped_data, wrapped_data_len, 5695 2, addr, len, unwrapped) < 0) { 5696 wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed"); 5697 goto fail; 5698 } 5699 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 5700 unwrapped, unwrapped_len); 5701 5702 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 5703 wpa_printf(MSG_DEBUG, 5704 "DPP: Invalid attribute in unwrapped data"); 5705 goto fail; 5706 } 5707 5708 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY, 5709 &b_key_len); 5710 if (!b_key || b_key_len != 2 * curve->prime_len) { 5711 wpa_printf(MSG_DEBUG, 5712 "DPP: No valid peer bootstrapping key found"); 5713 goto fail; 5714 } 5715 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key, 5716 b_key_len); 5717 if (!pkex->peer_bootstrap_key) 5718 goto fail; 5719 dpp_debug_print_key("DPP: Peer bootstrap public key", 5720 pkex->peer_bootstrap_key); 5721 5722 /* ECDH: J' = y * A' */ 5723 EVP_PKEY_CTX_free(ctx); 5724 ctx = EVP_PKEY_CTX_new(pkex->y, NULL); 5725 if (!ctx || 5726 EVP_PKEY_derive_init(ctx) != 1 || 5727 EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 || 5728 EVP_PKEY_derive(ctx, NULL, &Jx_len) != 1 || 5729 Jx_len > DPP_MAX_SHARED_SECRET_LEN || 5730 EVP_PKEY_derive(ctx, Jx, &Jx_len) != 1) { 5731 wpa_printf(MSG_ERROR, 5732 "DPP: Failed to derive ECDH shared secret: %s", 5733 ERR_error_string(ERR_get_error(), NULL)); 5734 goto fail; 5735 } 5736 5737 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (J.x)", 5738 Jx, Jx_len); 5739 5740 /* u' = HMAC(J'.x, MAC-Initiator | A'.x | Y.x | X'.x) */ 5741 A_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0); 5742 Y_pub = dpp_get_pubkey_point(pkex->y, 0); 5743 X_pub = dpp_get_pubkey_point(pkex->x, 0); 5744 if (!A_pub || !Y_pub || !X_pub) 5745 goto fail; 5746 addr[0] = pkex->peer_mac; 5747 len[0] = ETH_ALEN; 5748 addr[1] = wpabuf_head(A_pub); 5749 len[1] = wpabuf_len(A_pub) / 2; 5750 addr[2] = wpabuf_head(Y_pub); 5751 len[2] = wpabuf_len(Y_pub) / 2; 5752 addr[3] = wpabuf_head(X_pub); 5753 len[3] = wpabuf_len(X_pub) / 2; 5754 if (dpp_hmac_vector(curve->hash_len, Jx, Jx_len, 4, addr, len, u) < 0) 5755 goto fail; 5756 5757 peer_u = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_I_AUTH_TAG, 5758 &peer_u_len); 5759 if (!peer_u || peer_u_len != curve->hash_len || 5760 os_memcmp(peer_u, u, curve->hash_len) != 0) { 5761 wpa_printf(MSG_DEBUG, "DPP: No valid u (I-Auth tag) found"); 5762 wpa_hexdump(MSG_DEBUG, "DPP: Calculated u'", 5763 u, curve->hash_len); 5764 wpa_hexdump(MSG_DEBUG, "DPP: Received u", peer_u, peer_u_len); 5765 goto fail; 5766 } 5767 wpa_printf(MSG_DEBUG, "DPP: Valid u (I-Auth tag) received"); 5768 5769 /* ECDH: L = b * X' */ 5770 EVP_PKEY_CTX_free(ctx); 5771 ctx = EVP_PKEY_CTX_new(pkex->own_bi->pubkey, NULL); 5772 if (!ctx || 5773 EVP_PKEY_derive_init(ctx) != 1 || 5774 EVP_PKEY_derive_set_peer(ctx, pkex->x) != 1 || 5775 EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 || 5776 Lx_len > DPP_MAX_SHARED_SECRET_LEN || 5777 EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) { 5778 wpa_printf(MSG_ERROR, 5779 "DPP: Failed to derive ECDH shared secret: %s", 5780 ERR_error_string(ERR_get_error(), NULL)); 5781 goto fail; 5782 } 5783 5784 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)", 5785 Lx, Lx_len); 5786 5787 /* v = HMAC(L.x, MAC-Responder | B.x | X'.x | Y.x) */ 5788 B_pub = dpp_get_pubkey_point(pkex->own_bi->pubkey, 0); 5789 if (!B_pub) 5790 goto fail; 5791 addr[0] = pkex->own_mac; 5792 len[0] = ETH_ALEN; 5793 addr[1] = wpabuf_head(B_pub); 5794 len[1] = wpabuf_len(B_pub) / 2; 5795 addr[2] = wpabuf_head(X_pub); 5796 len[2] = wpabuf_len(X_pub) / 2; 5797 addr[3] = wpabuf_head(Y_pub); 5798 len[3] = wpabuf_len(Y_pub) / 2; 5799 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0) 5800 goto fail; 5801 wpa_hexdump(MSG_DEBUG, "DPP: v", v, curve->hash_len); 5802 5803 /* {B, v [bootstrapping info]}z */ 5804 clear_len = 4 + 2 * curve->prime_len + 4 + curve->hash_len; 5805 clear = wpabuf_alloc(clear_len); 5806 msg = dpp_alloc_msg(DPP_PA_PKEX_COMMIT_REVEAL_RESP, 5807 4 + clear_len + AES_BLOCK_SIZE); 5808 if (!clear || !msg) 5809 goto fail; 5810 5811 /* A in Bootstrap Key attribute */ 5812 wpabuf_put_le16(clear, DPP_ATTR_BOOTSTRAP_KEY); 5813 wpabuf_put_le16(clear, wpabuf_len(B_pub)); 5814 wpabuf_put_buf(clear, B_pub); 5815 5816 /* v in R-Auth tag attribute */ 5817 wpabuf_put_le16(clear, DPP_ATTR_R_AUTH_TAG); 5818 wpabuf_put_le16(clear, curve->hash_len); 5819 wpabuf_put_data(clear, v, curve->hash_len); 5820 5821 addr[0] = wpabuf_head_u8(msg) + 2; 5822 len[0] = DPP_HDR_LEN; 5823 octet = 1; 5824 addr[1] = &octet; 5825 len[1] = sizeof(octet); 5826 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 5827 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 5828 5829 wpabuf_put_le16(msg, DPP_ATTR_WRAPPED_DATA); 5830 wpabuf_put_le16(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 5831 wrapped = wpabuf_put(msg, wpabuf_len(clear) + AES_BLOCK_SIZE); 5832 5833 wpa_hexdump_buf(MSG_DEBUG, "DPP: AES-SIV cleartext", clear); 5834 if (aes_siv_encrypt(pkex->z, curve->hash_len, 5835 wpabuf_head(clear), wpabuf_len(clear), 5836 2, addr, len, wrapped) < 0) 5837 goto fail; 5838 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 5839 wrapped, wpabuf_len(clear) + AES_BLOCK_SIZE); 5840 out: 5841 EVP_PKEY_CTX_free(ctx); 5842 os_free(unwrapped); 5843 wpabuf_free(A_pub); 5844 wpabuf_free(B_pub); 5845 wpabuf_free(X_pub); 5846 wpabuf_free(Y_pub); 5847 wpabuf_free(clear); 5848 return msg; 5849 fail: 5850 wpabuf_free(msg); 5851 msg = NULL; 5852 goto out; 5853 } 5854 5855 5856 int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr, 5857 const u8 *buf, size_t buflen) 5858 { 5859 const struct dpp_curve_params *curve = pkex->own_bi->curve; 5860 const u8 *wrapped_data, *b_key, *peer_v; 5861 u16 wrapped_data_len, b_key_len, peer_v_len = 0; 5862 const u8 *addr[4]; 5863 size_t len[4]; 5864 u8 octet; 5865 u8 *unwrapped = NULL; 5866 size_t unwrapped_len = 0; 5867 int ret = -1; 5868 u8 v[DPP_MAX_HASH_LEN]; 5869 size_t Lx_len; 5870 u8 Lx[DPP_MAX_SHARED_SECRET_LEN]; 5871 EVP_PKEY_CTX *ctx = NULL; 5872 struct wpabuf *B_pub = NULL, *X_pub = NULL, *Y_pub = NULL; 5873 5874 wrapped_data = dpp_get_attr(buf, buflen, DPP_ATTR_WRAPPED_DATA, 5875 &wrapped_data_len); 5876 if (!wrapped_data || wrapped_data_len < AES_BLOCK_SIZE) { 5877 wpa_printf(MSG_DEBUG, 5878 "DPP: Missing or invalid required Wrapped data attribute"); 5879 goto fail; 5880 } 5881 5882 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV ciphertext", 5883 wrapped_data, wrapped_data_len); 5884 unwrapped_len = wrapped_data_len - AES_BLOCK_SIZE; 5885 unwrapped = os_malloc(unwrapped_len); 5886 if (!unwrapped) 5887 goto fail; 5888 5889 addr[0] = hdr; 5890 len[0] = DPP_HDR_LEN; 5891 octet = 1; 5892 addr[1] = &octet; 5893 len[1] = sizeof(octet); 5894 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[0]", addr[0], len[0]); 5895 wpa_hexdump(MSG_DEBUG, "DDP: AES-SIV AD[1]", addr[1], len[1]); 5896 5897 if (aes_siv_decrypt(pkex->z, curve->hash_len, 5898 wrapped_data, wrapped_data_len, 5899 2, addr, len, unwrapped) < 0) { 5900 wpa_printf(MSG_DEBUG, "DPP: AES-SIV decryption failed"); 5901 goto fail; 5902 } 5903 wpa_hexdump(MSG_DEBUG, "DPP: AES-SIV cleartext", 5904 unwrapped, unwrapped_len); 5905 5906 if (dpp_check_attrs(unwrapped, unwrapped_len) < 0) { 5907 wpa_printf(MSG_DEBUG, 5908 "DPP: Invalid attribute in unwrapped data"); 5909 goto fail; 5910 } 5911 5912 b_key = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_BOOTSTRAP_KEY, 5913 &b_key_len); 5914 if (!b_key || b_key_len != 2 * curve->prime_len) { 5915 wpa_printf(MSG_DEBUG, 5916 "DPP: No valid peer bootstrapping key found"); 5917 goto fail; 5918 } 5919 pkex->peer_bootstrap_key = dpp_set_pubkey_point(pkex->x, b_key, 5920 b_key_len); 5921 if (!pkex->peer_bootstrap_key) 5922 goto fail; 5923 dpp_debug_print_key("DPP: Peer bootstrap public key", 5924 pkex->peer_bootstrap_key); 5925 5926 /* ECDH: L' = x * B' */ 5927 ctx = EVP_PKEY_CTX_new(pkex->x, NULL); 5928 if (!ctx || 5929 EVP_PKEY_derive_init(ctx) != 1 || 5930 EVP_PKEY_derive_set_peer(ctx, pkex->peer_bootstrap_key) != 1 || 5931 EVP_PKEY_derive(ctx, NULL, &Lx_len) != 1 || 5932 Lx_len > DPP_MAX_SHARED_SECRET_LEN || 5933 EVP_PKEY_derive(ctx, Lx, &Lx_len) != 1) { 5934 wpa_printf(MSG_ERROR, 5935 "DPP: Failed to derive ECDH shared secret: %s", 5936 ERR_error_string(ERR_get_error(), NULL)); 5937 goto fail; 5938 } 5939 5940 wpa_hexdump_key(MSG_DEBUG, "DPP: ECDH shared secret (L.x)", 5941 Lx, Lx_len); 5942 5943 /* v' = HMAC(L.x, MAC-Responder | B'.x | X.x | Y'.x) */ 5944 B_pub = dpp_get_pubkey_point(pkex->peer_bootstrap_key, 0); 5945 X_pub = dpp_get_pubkey_point(pkex->x, 0); 5946 Y_pub = dpp_get_pubkey_point(pkex->y, 0); 5947 if (!B_pub || !X_pub || !Y_pub) 5948 goto fail; 5949 addr[0] = pkex->peer_mac; 5950 len[0] = ETH_ALEN; 5951 addr[1] = wpabuf_head(B_pub); 5952 len[1] = wpabuf_len(B_pub) / 2; 5953 addr[2] = wpabuf_head(X_pub); 5954 len[2] = wpabuf_len(X_pub) / 2; 5955 addr[3] = wpabuf_head(Y_pub); 5956 len[3] = wpabuf_len(Y_pub) / 2; 5957 if (dpp_hmac_vector(curve->hash_len, Lx, Lx_len, 4, addr, len, v) < 0) 5958 goto fail; 5959 5960 peer_v = dpp_get_attr(unwrapped, unwrapped_len, DPP_ATTR_R_AUTH_TAG, 5961 &peer_v_len); 5962 if (!peer_v || peer_v_len != curve->hash_len || 5963 os_memcmp(peer_v, v, curve->hash_len) != 0) { 5964 wpa_printf(MSG_DEBUG, "DPP: No valid v (R-Auth tag) found"); 5965 wpa_hexdump(MSG_DEBUG, "DPP: Calculated v'", 5966 v, curve->hash_len); 5967 wpa_hexdump(MSG_DEBUG, "DPP: Received v", peer_v, peer_v_len); 5968 goto fail; 5969 } 5970 wpa_printf(MSG_DEBUG, "DPP: Valid v (R-Auth tag) received"); 5971 5972 ret = 0; 5973 out: 5974 wpabuf_free(B_pub); 5975 wpabuf_free(X_pub); 5976 wpabuf_free(Y_pub); 5977 EVP_PKEY_CTX_free(ctx); 5978 os_free(unwrapped); 5979 return ret; 5980 fail: 5981 goto out; 5982 } 5983 5984 5985 void dpp_pkex_free(struct dpp_pkex *pkex) 5986 { 5987 if (!pkex) 5988 return; 5989 5990 os_free(pkex->identifier); 5991 os_free(pkex->code); 5992 EVP_PKEY_free(pkex->x); 5993 EVP_PKEY_free(pkex->y); 5994 EVP_PKEY_free(pkex->peer_bootstrap_key); 5995 wpabuf_free(pkex->exchange_req); 5996 wpabuf_free(pkex->exchange_resp); 5997 os_free(pkex); 5998 } 5999