#include <openssl/core_names.h>
#include <openssl/param_build.h>
#include <openssl/rsa.h>
+#include <openssl/encoder.h>
#include <openssl/decoder.h>
#else /* OpenSSL version >= 3.0 */
#include <openssl/cmac.h>
struct crypto_ec {
EC_GROUP *group;
int nid;
+ int iana_group;
BN_CTX *bnctx;
BIGNUM *prime;
BIGNUM *order;
}
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+static const char * crypto_ec_group_2_name(int group)
+{
+ /* Map from IANA registry for IKE D-H groups to OpenSSL group name */
+ switch (group) {
+ case 19:
+ return "prime256v1";
+ case 20:
+ return "secp384r1";
+ case 21:
+ return "secp521r1";
+ case 25:
+ return "prime192v1";
+ case 26:
+ return "secp224r1";
+#ifdef NID_brainpoolP224r1
+ case 27:
+ return "brainpoolP224r1";
+#endif /* NID_brainpoolP224r1 */
+#ifdef NID_brainpoolP256r1
+ case 28:
+ return "brainpoolP256r1";
+#endif /* NID_brainpoolP256r1 */
+#ifdef NID_brainpoolP384r1
+ case 29:
+ return "brainpoolP384r1";
+#endif /* NID_brainpoolP384r1 */
+#ifdef NID_brainpoolP512r1
+ case 30:
+ return "brainpoolP512r1";
+#endif /* NID_brainpoolP512r1 */
+ default:
+ return NULL;
+ }
+}
+#endif /* OpenSSL version >= 3.0 */
+
+
struct crypto_ec * crypto_ec_init(int group)
{
struct crypto_ec *e;
return NULL;
e->nid = nid;
+ e->iana_group = group;
e->bnctx = BN_CTX_new();
e->group = EC_GROUP_new_by_curve_name(nid);
e->prime = BN_new();
struct crypto_ec_key * crypto_ec_key_set_pub(int group, const u8 *buf_x,
const u8 *buf_y, size_t len)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ const char *group_name;
+ OSSL_PARAM params[3];
+ u8 *pub;
+ EVP_PKEY_CTX *ctx;
+ EVP_PKEY *pkey = NULL;
+
+ group_name = crypto_ec_group_2_name(group);
+ if (!group_name)
+ return NULL;
+
+ pub = os_malloc(1 + len * 2);
+ if (!pub)
+ return NULL;
+ pub[0] = 0x04; /* uncompressed */
+ os_memcpy(pub + 1, buf_x, len);
+ os_memcpy(pub + 1 + len, buf_y, len);
+
+ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
+ (char *) group_name, 0);
+ params[1] = OSSL_PARAM_construct_octet_string(OSSL_PKEY_PARAM_PUB_KEY,
+ pub, 1 + len * 2);
+ params[2] = OSSL_PARAM_construct_end();
+
+ ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
+ if (!ctx) {
+ os_free(pub);
+ return NULL;
+ }
+ if (EVP_PKEY_fromdata_init(ctx) <= 0 ||
+ EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) <= 0) {
+ os_free(pub);
+ EVP_PKEY_CTX_free(ctx);
+ return NULL;
+ }
+
+ os_free(pub);
+ EVP_PKEY_CTX_free(ctx);
+
+ return (struct crypto_ec_key *) pkey;
+#else /* OpenSSL version >= 3.0 */
EC_KEY *eckey = NULL;
EVP_PKEY *pkey = NULL;
EC_GROUP *ec_group = NULL;
EVP_PKEY_free(pkey);
pkey = NULL;
goto out;
+#endif /* OpenSSL version >= 3.0 */
}
crypto_ec_key_set_pub_point(struct crypto_ec *ec,
const struct crypto_ec_point *pub)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ int len = BN_num_bytes(ec->prime);
+ struct crypto_ec_key *key;
+ u8 *buf;
+
+ buf = os_malloc(2 * len);
+ if (!buf)
+ return NULL;
+ if (crypto_ec_point_to_bin(ec, pub, buf, buf + len) < 0) {
+ os_free(buf);
+ return NULL;
+ }
+
+ key = crypto_ec_key_set_pub(ec->iana_group, buf, buf + len, len);
+ os_free(buf);
+
+ return key;
+#else /* OpenSSL version >= 3.0 */
EC_KEY *eckey;
EVP_PKEY *pkey = NULL;
+ wpa_printf(MSG_INFO, "JKM:%s", __func__);
eckey = EC_KEY_new();
if (!eckey ||
EC_KEY_set_group(eckey, ec->group) != 1 ||
EC_KEY_free(eckey);
pkey = NULL;
goto out;
+#endif /* OpenSSL version >= 3.0 */
}
struct crypto_ec_key * crypto_ec_key_gen(int group)
{
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ EVP_PKEY_CTX *ctx;
+ OSSL_PARAM params[2];
+ const char *group_name;
+ EVP_PKEY *pkey = NULL;
+
+ group_name = crypto_ec_group_2_name(group);
+ if (!group_name)
+ return NULL;
+
+ params[0] = OSSL_PARAM_construct_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME,
+ (char *) group_name, 0);
+ params[1] = OSSL_PARAM_construct_end();
+
+ ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
+ if (!ctx ||
+ EVP_PKEY_keygen_init(ctx) != 1 ||
+ EVP_PKEY_CTX_set_params(ctx, params) != 1 ||
+ EVP_PKEY_generate(ctx, &pkey) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: failed to generate EC keypair: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ pkey = NULL;
+ }
+
+ EVP_PKEY_CTX_free(ctx);
+
+ return (struct crypto_ec_key *) pkey;
+#else /* OpenSSL version >= 3.0 */
EVP_PKEY_CTX *kctx = NULL;
EC_KEY *ec_params = NULL, *eckey;
EVP_PKEY *params = NULL, *key = NULL;
EVP_PKEY_free(params);
EVP_PKEY_CTX_free(kctx);
return (struct crypto_ec_key *) key;
+#endif /* OpenSSL version >= 3.0 */
}
struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key)
{
+ EVP_PKEY *pkey = (EVP_PKEY *) key;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ OSSL_ENCODER_CTX *ctx;
+ int selection;
+ unsigned char *pdata = NULL;
+ size_t pdata_len = 0;
+ EVP_PKEY *copy = NULL;
+ struct wpabuf *buf = NULL;
+
+ if (EVP_PKEY_get_ec_point_conv_form(pkey) !=
+ POINT_CONVERSION_COMPRESSED) {
+ copy = EVP_PKEY_dup(pkey);
+ if (!copy)
+ return NULL;
+ if (EVP_PKEY_set_utf8_string_param(
+ copy, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT,
+ OSSL_PKEY_EC_POINT_CONVERSION_FORMAT_COMPRESSED) !=
+ 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to set compressed format");
+ EVP_PKEY_free(copy);
+ return NULL;
+ }
+ pkey = copy;
+ }
+
+ selection = OSSL_KEYMGMT_SELECT_ALL_PARAMETERS |
+ OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
+
+ ctx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, "DER",
+ "SubjectPublicKeyInfo",
+ NULL);
+ if (!ctx || OSSL_ENCODER_to_data(ctx, &pdata, &pdata_len) != 1) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to encode SubjectPublicKeyInfo: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ pdata = NULL;
+ }
+ OSSL_ENCODER_CTX_free(ctx);
+ if (pdata) {
+ buf = wpabuf_alloc_copy(pdata, pdata_len);
+ OPENSSL_free(pdata);
+ }
+
+ EVP_PKEY_free(copy);
+
+ return buf;
+#else /* OpenSSL version >= 3.0 */
#ifdef OPENSSL_IS_BORINGSSL
unsigned char *der = NULL;
int der_len;
int nid;
ctx = BN_CTX_new();
- eckey = EVP_PKEY_get0_EC_KEY((EVP_PKEY *) key);
+ eckey = EVP_PKEY_get0_EC_KEY(pkey);
if (!ctx || !eckey)
goto fail;
int der_len;
struct wpabuf *buf;
EC_KEY *eckey;
-#if OPENSSL_VERSION_NUMBER >= 0x30000000L
- EVP_PKEY *tmp;
-#endif /* OpenSSL version >= 3.0 */
- eckey = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) key);
+ eckey = EVP_PKEY_get1_EC_KEY(pkey);
if (!eckey)
return NULL;
/* For now, all users expect COMPRESSED form */
EC_KEY_set_conv_form(eckey, POINT_CONVERSION_COMPRESSED);
-#if OPENSSL_VERSION_NUMBER >= 0x30000000L
- tmp = EVP_PKEY_new();
- if (!tmp)
- return NULL;
- if (EVP_PKEY_set1_EC_KEY(tmp, eckey) != 1) {
- EVP_PKEY_free(tmp);
- return NULL;
- }
- key = (struct crypto_ec_key *) tmp;
-#endif /* OpenSSL version >= 3.0 */
-
der_len = i2d_PUBKEY((EVP_PKEY *) key, &der);
EC_KEY_free(eckey);
-#if OPENSSL_VERSION_NUMBER >= 0x30000000L
- EVP_PKEY_free(tmp);
-#endif /* OpenSSL version >= 3.0 */
if (der_len <= 0) {
wpa_printf(MSG_INFO, "OpenSSL: i2d_PUBKEY() failed: %s",
ERR_error_string(ERR_get_error(), NULL));
OPENSSL_free(der);
return buf;
#endif /* OPENSSL_IS_BORINGSSL */
+#endif /* OpenSSL version >= 3.0 */
}
struct wpabuf * crypto_ec_key_get_ecprivate_key(struct crypto_ec_key *key,
bool include_pub)
{
+ EVP_PKEY *pkey = (EVP_PKEY *) key;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ OSSL_ENCODER_CTX *ctx;
+ int selection;
+ unsigned char *pdata = NULL;
+ size_t pdata_len = 0;
+ struct wpabuf *buf;
+ EVP_PKEY *copy = NULL;
+
+ selection = OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS |
+ OSSL_KEYMGMT_SELECT_PRIVATE_KEY;
+ if (include_pub) {
+ selection |= OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
+ } else {
+ /* Not including OSSL_KEYMGMT_SELECT_PUBLIC_KEY does not seem
+ * to really be sufficient, so clone the key and explicitly
+ * mark it not to include the public key. */
+ copy = EVP_PKEY_dup(pkey);
+ if (!copy)
+ return NULL;
+ EVP_PKEY_set_int_param(copy, OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC,
+ 0);
+ pkey = copy;
+ }
+
+ ctx = OSSL_ENCODER_CTX_new_for_pkey(pkey, selection, "DER",
+ "type-specific", NULL);
+ if (!ctx || OSSL_ENCODER_to_data(ctx, &pdata, &pdata_len) != 1) {
+ OSSL_ENCODER_CTX_free(ctx);
+ EVP_PKEY_free(copy);
+ return NULL;
+ }
+ OSSL_ENCODER_CTX_free(ctx);
+ buf = wpabuf_alloc_copy(pdata, pdata_len);
+ OPENSSL_free(pdata);
+ EVP_PKEY_free(copy);
+ return buf;
+#else /* OpenSSL version >= 3.0 */
EC_KEY *eckey;
unsigned char *der = NULL;
int der_len;
struct wpabuf *buf;
unsigned int key_flags;
- eckey = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) key);
+ eckey = EVP_PKEY_get1_EC_KEY(pkey);
if (!eckey)
return NULL;
OPENSSL_free(der);
return buf;
+#endif /* OpenSSL version >= 3.0 */
}
struct wpabuf * crypto_ec_key_get_pubkey_point(struct crypto_ec_key *key,
int prefix)
{
+ EVP_PKEY *pkey = (EVP_PKEY *) key;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ struct wpabuf *buf;
+ unsigned char *pos;
+ size_t pub_len = OSSL_PARAM_UNMODIFIED;
+
+ buf = NULL;
+ if (!EVP_PKEY_is_a(pkey, "EC") ||
+ EVP_PKEY_get_octet_string_param(pkey,
+ OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
+ NULL, 0, &pub_len) < 0 ||
+ pub_len == OSSL_PARAM_UNMODIFIED ||
+ !(buf = wpabuf_alloc(pub_len)) ||
+ EVP_PKEY_get_octet_string_param(pkey,
+ OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY,
+ wpabuf_put(buf, pub_len),
+ pub_len, NULL) != 1 ||
+ wpabuf_head_u8(buf)[0] != 0x04) {
+ wpa_printf(MSG_INFO,
+ "OpenSSL: Failed to get encoded public key: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ wpabuf_free(buf);
+ return NULL;
+ }
+
+ if (!prefix) {
+ /* Remove 0x04 prefix if requested */
+ pos = wpabuf_mhead(buf);
+ os_memmove(pos, pos + 1, pub_len - 1);
+ buf->used--;
+ }
+
+ return buf;
+#else /* OpenSSL version >= 3.0 */
int len, res;
EC_KEY *eckey;
struct wpabuf *buf;
unsigned char *pos;
- eckey = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) key);
+ eckey = EVP_PKEY_get1_EC_KEY(pkey);
if (!eckey)
return NULL;
EC_KEY_set_conv_form(eckey, POINT_CONVERSION_UNCOMPRESSED);
}
return buf;
+#endif /* OpenSSL version >= 3.0 */
}