|  | 
| 17 | 17 | #include "model/controller/dual_mode_controller.h" | 
| 18 | 18 | 
 | 
| 19 | 19 | #include <openssl/ec.h> | 
| 20 |  | -#include <openssl/ec_key.h> | 
| 21 |  | -#include <openssl/mem.h> | 
| 22 |  | -#include <openssl/nid.h> | 
|  | 20 | +#include <openssl/obj_mac.h> | 
|  | 21 | +#include <openssl/bn.h> | 
|  | 22 | +#include <openssl/err.h> | 
|  | 23 | +#include <openssl/evp.h> | 
| 23 | 24 | #include <packet_runtime.h> | 
| 24 | 25 | 
 | 
| 25 | 26 | #include <algorithm> | 
| @@ -2242,40 +2243,66 @@ void DualModeController::LeWriteSuggestedDefaultDataLength(CommandView command) | 
| 2242 | 2243 | 
 | 
| 2243 | 2244 | static ErrorCode generateP256Key(std::array<uint8_t, 32>& key_x_coordinate, | 
| 2244 | 2245 |                                  std::array<uint8_t, 32>& key_y_coordinate) { | 
| 2245 |  | -  auto ec_key = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); | 
| 2246 |  | -  if (!ec_key) { | 
| 2247 |  | -    WARNING("EC_KEY_new_by_curve_name(NID_X9_62_prime256v1) failed"); | 
| 2248 |  | -    return ErrorCode::UNSPECIFIED_ERROR; | 
| 2249 |  | -  } | 
|  | 2246 | +    // Clear any previous OpenSSL errors. | 
|  | 2247 | +    ERR_clear_error(); | 
|  | 2248 | + | 
|  | 2249 | +    // Use unique_ptr with custom deleters for automatic memory management | 
|  | 2250 | +    // This ensures resources are freed even if an early return occurs due | 
|  | 2251 | +    // to an error. | 
|  | 2252 | +    auto ec_key_deleter = [](EC_KEY* ptr) { EC_KEY_free(ptr); }; | 
|  | 2253 | +    std::unique_ptr<EC_KEY, decltype(ec_key_deleter)> ec_key( | 
|  | 2254 | +        EC_KEY_new_by_curve_name(NID_X9_62_prime256v1), ec_key_deleter); | 
|  | 2255 | + | 
|  | 2256 | +    if (!ec_key) { | 
|  | 2257 | +        WARNING("Failed to create EC_KEY for prime256v1 curve."); | 
|  | 2258 | +        return ErrorCode::UNSPECIFIED_ERROR; | 
|  | 2259 | +    } | 
| 2250 | 2260 | 
 | 
| 2251 |  | -  if (!EC_KEY_generate_key(ec_key)) { | 
| 2252 |  | -    WARNING("EC_KEY_generate_key failed"); | 
| 2253 |  | -    EC_KEY_free(ec_key); | 
| 2254 |  | -    return ErrorCode::UNSPECIFIED_ERROR; | 
| 2255 |  | -  } | 
|  | 2261 | +    // Generate the key pair. | 
|  | 2262 | +    if (!EC_KEY_generate_key(ec_key.get())) { | 
|  | 2263 | +        WARNING("Failed to generate EC key pair."); | 
|  | 2264 | +        return ErrorCode::UNSPECIFIED_ERROR; | 
|  | 2265 | +    } | 
| 2256 | 2266 | 
 | 
| 2257 |  | -  uint8_t* out_buf = nullptr; | 
| 2258 |  | -  auto size = EC_KEY_key2buf(ec_key, POINT_CONVERSION_UNCOMPRESSED, &out_buf, nullptr); | 
| 2259 |  | -  if (!out_buf) { | 
| 2260 |  | -    WARNING("EC_KEY_key2buf failed"); | 
| 2261 |  | -    EC_KEY_free(ec_key); | 
| 2262 |  | -    return ErrorCode::UNSPECIFIED_ERROR; | 
| 2263 |  | -  } | 
|  | 2267 | +    // Get the public key point and group. | 
|  | 2268 | +    const EC_POINT* pub_key_point = EC_KEY_get0_public_key(ec_key.get()); | 
|  | 2269 | +    const EC_GROUP* ec_group = EC_KEY_get0_group(ec_key.get()); | 
| 2264 | 2270 | 
 | 
| 2265 |  | -  const size_t expected_size = key_x_coordinate.size() + key_y_coordinate.size() + 1; | 
| 2266 |  | -  if (size != expected_size) { | 
| 2267 |  | -    WARNING("unexpected size {}", size); | 
| 2268 |  | -    OPENSSL_free(out_buf); | 
| 2269 |  | -    EC_KEY_free(ec_key); | 
| 2270 |  | -    return ErrorCode::UNSPECIFIED_ERROR; | 
| 2271 |  | -  } | 
|  | 2271 | +    if (!pub_key_point || !ec_group) { | 
|  | 2272 | +        WARNING("Failed to get public key point or EC group."); | 
|  | 2273 | +        return ErrorCode::UNSPECIFIED_ERROR; | 
|  | 2274 | +    } | 
|  | 2275 | + | 
|  | 2276 | +    // BIGNUM objects to hold the x and y coordinates | 
|  | 2277 | +    auto bn_deleter = [](BIGNUM* ptr) { BN_free(ptr); }; | 
|  | 2278 | +    std::unique_ptr<BIGNUM, decltype(bn_deleter)> x_bn(BN_new(), bn_deleter); | 
|  | 2279 | +    std::unique_ptr<BIGNUM, decltype(bn_deleter)> y_bn(BN_new(), bn_deleter); | 
| 2272 | 2280 | 
 | 
| 2273 |  | -  memcpy(key_x_coordinate.data(), out_buf + 1, key_x_coordinate.size()); | 
| 2274 |  | -  memcpy(key_y_coordinate.data(), out_buf + 1 + key_x_coordinate.size(), key_y_coordinate.size()); | 
|  | 2281 | +    if (!x_bn || !y_bn) { | 
|  | 2282 | +        WARNING("Failed to allocate BIGNUMs for coordinates."); | 
|  | 2283 | +        return ErrorCode::UNSPECIFIED_ERROR; | 
|  | 2284 | +    } | 
|  | 2285 | + | 
|  | 2286 | +    // Extract affine coordinates (x, y) from the public key point | 
|  | 2287 | +    if (!EC_POINT_get_affine_coordinates(ec_group, pub_key_point, x_bn.get(), y_bn.get(), NULL)) { | 
|  | 2288 | +        WARNING("Failed to get affine coordinates from public key."); | 
|  | 2289 | +        return ErrorCode::UNSPECIFIED_ERROR; | 
|  | 2290 | +    } | 
|  | 2291 | + | 
|  | 2292 | +    // Convert BIGNUMs to fixed-size byte arrays (32 bytes for P-256) | 
|  | 2293 | +    // BN_bn2binpad pads with zeros if the BIGNUM is smaller than 'len'. | 
|  | 2294 | +    // It returns the number of bytes written, or -1 on error. | 
|  | 2295 | +    if (BN_bn2binpad(x_bn.get(), key_x_coordinate.data(), key_x_coordinate.size()) == -1) { | 
|  | 2296 | +        WARNING("Failed to convert X coordinate BIGNUM to binary."); | 
|  | 2297 | +        return ErrorCode::UNSPECIFIED_ERROR; | 
|  | 2298 | +    } | 
|  | 2299 | + | 
|  | 2300 | +    if (BN_bn2binpad(y_bn.get(), key_y_coordinate.data(), key_y_coordinate.size()) == -1) { | 
|  | 2301 | +        WARNING("Failed to convert Y coordinate BIGNUM to binary."); | 
|  | 2302 | +        return ErrorCode::UNSPECIFIED_ERROR; | 
|  | 2303 | +    } | 
| 2275 | 2304 | 
 | 
| 2276 |  | -  // OPENSSL_free(out_buf); // <-- this call fails with error invalid pointer | 
| 2277 |  | -  EC_KEY_free(ec_key); | 
| 2278 |  | -  return ErrorCode::SUCCESS; | 
|  | 2305 | +    return ErrorCode::SUCCESS; | 
| 2279 | 2306 | } | 
| 2280 | 2307 | 
 | 
| 2281 | 2308 | void DualModeController::LeReadLocalP256PublicKey(CommandView command) { | 
|  | 
0 commit comments