]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
OpenSSL: Additional EC functionality for SAE-PK
authorJouni Malinen <jouni@codeaurora.org>
Sat, 30 May 2020 20:30:42 +0000 (23:30 +0300)
committerJouni Malinen <j@w1.fi>
Tue, 2 Jun 2020 14:56:45 +0000 (17:56 +0300)
These will be needed for implementing SAE-PK ECDSA signing and signature
verification operations.

Signed-off-by: Jouni Malinen <jouni@codeaurora.org>
src/crypto/crypto.h
src/crypto/crypto_openssl.c

index de2b07732903057664d8613fff0244566a236efa..7d2ebd61caea93e62f5510f13f9733cfea40657d 100644 (file)
@@ -918,4 +918,16 @@ struct wpabuf * crypto_ecdh_set_peerkey(struct crypto_ecdh *ecdh, int inc_y,
 void crypto_ecdh_deinit(struct crypto_ecdh *ecdh);
 size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh);
 
+struct crypto_ec_key;
+
+struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len);
+struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len);
+void crypto_ec_key_deinit(struct crypto_ec_key *key);
+struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key);
+struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data,
+                                  size_t len);
+int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data,
+                                  size_t len, const u8 *sig, size_t sig_len);
+int crypto_ec_key_group(struct crypto_ec_key *key);
+
 #endif /* CRYPTO_H */
index 47b6ebbd6ebee8b382b5f78e040f4b9e1e9bbd06..54bfcd25f4ba299bc9c288ffc1b96a42324c37b2 100644 (file)
@@ -21,6 +21,7 @@
 #endif /* CONFIG_OPENSSL_CMAC */
 #ifdef CONFIG_ECC
 #include <openssl/ec.h>
+#include <openssl/x509.h>
 #endif /* CONFIG_ECC */
 
 #include "common.h"
@@ -79,6 +80,14 @@ static void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
        bin_clear_free(ctx, sizeof(*ctx));
 }
 
+
+static EC_KEY * EVP_PKEY_get0_EC_KEY(EVP_PKEY *pkey)
+{
+       if (pkey->type != EVP_PKEY_EC)
+               return NULL;
+       return pkey->pkey.ec;
+}
+
 #endif /* OpenSSL version < 1.1.0 */
 
 static BIGNUM * get_group5_prime(void)
@@ -2174,4 +2183,159 @@ size_t crypto_ecdh_prime_len(struct crypto_ecdh *ecdh)
        return crypto_ec_prime_len(ecdh->ec);
 }
 
+
+struct crypto_ec_key {
+       EVP_PKEY *pkey;
+       EC_KEY *eckey;
+       BIGNUM *kinv;
+       BIGNUM *rp;
+};
+
+
+struct crypto_ec_key * crypto_ec_key_parse_priv(const u8 *der, size_t der_len)
+{
+       struct crypto_ec_key *key;
+
+       key = os_zalloc(sizeof(*key));
+       if (!key)
+               return NULL;
+
+       key->eckey = d2i_ECPrivateKey(NULL, &der, der_len);
+       if (!key->eckey) {
+               wpa_printf(MSG_INFO, "OpenSSL: d2i_ECPrivateKey() failed: %s",
+                          ERR_error_string(ERR_get_error(), NULL));
+               goto fail;
+       }
+       EC_KEY_set_conv_form(key->eckey, POINT_CONVERSION_COMPRESSED);
+
+       key->pkey = EVP_PKEY_new();
+       if (!key->pkey || EVP_PKEY_assign_EC_KEY(key->pkey, key->eckey) != 1) {
+               EC_KEY_free(key->eckey);
+               key->eckey = NULL;
+               goto fail;
+       }
+
+       if (ECDSA_sign_setup(key->eckey, NULL, &key->kinv, &key->rp) != 1)
+               goto fail;
+       return key;
+fail:
+       crypto_ec_key_deinit(key);
+       return NULL;
+}
+
+
+struct crypto_ec_key * crypto_ec_key_parse_pub(const u8 *der, size_t der_len)
+{
+       struct crypto_ec_key *key;
+
+       key = os_zalloc(sizeof(*key));
+       if (!key)
+               return NULL;
+
+       key->pkey = d2i_PUBKEY(NULL, &der, der_len);
+       if (!key->pkey) {
+               wpa_printf(MSG_INFO, "OpenSSL: d2i_PUBKEY() failed: %s",
+                          ERR_error_string(ERR_get_error(), NULL));
+               goto fail;
+       }
+
+       key->eckey = EVP_PKEY_get0_EC_KEY(key->pkey);
+       if (!key->eckey)
+               goto fail;
+       return key;
+fail:
+       crypto_ec_key_deinit(key);
+       return NULL;
+}
+
+
+void crypto_ec_key_deinit(struct crypto_ec_key *key)
+{
+       if (key) {
+               EVP_PKEY_free(key->pkey);
+               BN_clear_free(key->kinv);
+               BN_clear_free(key->rp);
+               os_free(key);
+       }
+}
+
+
+struct wpabuf * crypto_ec_key_get_subject_public_key(struct crypto_ec_key *key)
+{
+       unsigned char *der = NULL;
+       int der_len;
+       struct wpabuf *buf;
+
+       der_len = i2d_PUBKEY(key->pkey, &der);
+       if (der_len <= 0) {
+               wpa_printf(MSG_INFO, "OpenSSL: i2d_PUBKEY() failed: %s",
+                          ERR_error_string(ERR_get_error(), NULL));
+               return NULL;
+       }
+
+       buf = wpabuf_alloc_copy(der, der_len);
+       OPENSSL_free(der);
+       return buf;
+}
+
+
+struct wpabuf * crypto_ec_key_sign(struct crypto_ec_key *key, const u8 *data,
+                                  size_t len)
+{
+       struct wpabuf *sig_der;
+       int res;
+       unsigned int sig_len;
+
+       sig_len = ECDSA_size(key->eckey);
+       sig_der = wpabuf_alloc(sig_len);
+       if (!sig_der)
+               return NULL;
+       res = ECDSA_sign_ex(0, data, len, wpabuf_put(sig_der, 0), &sig_len,
+                           key->kinv, key->rp, key->eckey);
+       if (res != 1) {
+               wpabuf_free(sig_der);
+               return NULL;
+       }
+       wpabuf_put(sig_der, sig_len);
+
+       return sig_der;
+}
+
+
+int crypto_ec_key_verify_signature(struct crypto_ec_key *key, const u8 *data,
+                                  size_t len, const u8 *sig, size_t sig_len)
+{
+       int ret;
+
+       ret = ECDSA_verify(0, data, len, sig, sig_len, key->eckey);
+       if (ret == 1)
+               return 1; /* signature ok */
+       if (ret == 0)
+               return 0; /* incorrect signature */
+       wpa_printf(MSG_INFO, "OpenSSL: ECDSA_verify() failed: %s",
+                  ERR_error_string(ERR_get_error(), NULL));
+       return -1;
+}
+
+
+int crypto_ec_key_group(struct crypto_ec_key *key)
+{
+       const EC_GROUP *group;
+       int nid;
+
+       group = EC_KEY_get0_group(key->eckey);
+       if (!group)
+               return -1;
+       nid = EC_GROUP_get_curve_name(group);
+       switch (nid) {
+       case NID_X9_62_prime256v1:
+               return 19;
+       case NID_secp384r1:
+               return 20;
+       case NID_secp521r1:
+               return 21;
+       }
+       return -1;
+}
+
 #endif /* CONFIG_ECC */