]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
EAP peer: Add a concept of a separate machine credential
authorJouni Malinen <j@w1.fi>
Tue, 20 Aug 2019 10:10:34 +0000 (13:10 +0300)
committerJouni Malinen <j@w1.fi>
Tue, 20 Aug 2019 10:24:14 +0000 (13:24 +0300)
This is an initial step in adding support for configuring separate user
and machine credentials. The new wpa_supplicant network profile
parameters machine_identity and machine_password are similar to the
existing identity and password, but explicitly assigned for the purpose
of machine authentication.

This commit alone does not change actual EAP peer method behavior as
separate commits are needed to determine when there is an explicit
request for machine authentication. Furthermore, this is only addressing
the username/password credential type, i.e., additional changes
following this design approach will be needed for certificate
credentials.

Signed-off-by: Jouni Malinen <j@w1.fi>
src/eap_peer/eap.c
src/eap_peer/eap_config.h
src/eap_peer/eap_i.h
wpa_supplicant/config.c
wpa_supplicant/config_file.c

index ada3c6db639ffe3ea8b20659cb028ed7bc8b5459..edec4586c2af1d9ec20e9a63d63d1f80eb3bca0a 100644 (file)
@@ -266,6 +266,7 @@ SM_STATE(EAP, INITIALIZE)
        sm->expected_failure = 0;
        sm->reauthInit = FALSE;
        sm->erp_seq = (u32) -1;
+       sm->use_machine_cred = 0;
 }
 
 
@@ -1675,6 +1676,11 @@ struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted)
                identity_len = config->anonymous_identity_len;
                wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
                                  identity, identity_len);
+       } else if (sm->use_machine_cred) {
+               identity = config->machine_identity;
+               identity_len = config->machine_identity_len;
+               wpa_hexdump_ascii(MSG_DEBUG, "EAP: using machine identity",
+                                 identity, identity_len);
        } else {
                identity = config->identity;
                identity_len = config->identity_len;
@@ -2741,8 +2747,15 @@ struct eap_peer_config * eap_get_config(struct eap_sm *sm)
 const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
 {
        struct eap_peer_config *config = eap_get_config(sm);
-       if (config == NULL)
+
+       if (!config)
                return NULL;
+
+       if (sm->use_machine_cred) {
+               *len = config->machine_identity_len;
+               return config->machine_identity;
+       }
+
        *len = config->identity_len;
        return config->identity;
 }
@@ -2752,14 +2765,24 @@ static int eap_get_ext_password(struct eap_sm *sm,
                                struct eap_peer_config *config)
 {
        char *name;
+       const u8 *password;
+       size_t password_len;
 
-       if (config->password == NULL)
+       if (sm->use_machine_cred) {
+               password = config->machine_password;
+               password_len = config->machine_password_len;
+       } else {
+               password = config->password;
+               password_len = config->password_len;
+       }
+
+       if (!password)
                return -1;
 
-       name = os_zalloc(config->password_len + 1);
-       if (name == NULL)
+       name = os_zalloc(password_len + 1);
+       if (!name)
                return -1;
-       os_memcpy(name, config->password, config->password_len);
+       os_memcpy(name, password, password_len);
 
        ext_password_free(sm->ext_pw_buf);
        sm->ext_pw_buf = ext_password_get(sm->ext_pw, name);
@@ -2778,16 +2801,25 @@ static int eap_get_ext_password(struct eap_sm *sm,
 const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
 {
        struct eap_peer_config *config = eap_get_config(sm);
-       if (config == NULL)
+
+       if (!config)
                return NULL;
 
-       if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+       if ((sm->use_machine_cred &&
+            (config->flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD)) ||
+           (!sm->use_machine_cred &&
+            (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD))) {
                if (eap_get_ext_password(sm, config) < 0)
                        return NULL;
                *len = wpabuf_len(sm->ext_pw_buf);
                return wpabuf_head(sm->ext_pw_buf);
        }
 
+       if (sm->use_machine_cred) {
+               *len = config->machine_password_len;
+               return config->machine_password;
+       }
+
        *len = config->password_len;
        return config->password;
 }
@@ -2805,10 +2837,14 @@ const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
 const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
 {
        struct eap_peer_config *config = eap_get_config(sm);
-       if (config == NULL)
+
+       if (!config)
                return NULL;
 
-       if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+       if ((sm->use_machine_cred &&
+            (config->flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD)) ||
+           (!sm->use_machine_cred &&
+            (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD))) {
                if (eap_get_ext_password(sm, config) < 0)
                        return NULL;
                if (hash)
@@ -2817,6 +2853,14 @@ const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
                return wpabuf_head(sm->ext_pw_buf);
        }
 
+       if (sm->use_machine_cred) {
+               *len = config->machine_password_len;
+               if (hash)
+                       *hash = !!(config->flags &
+                                  EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH);
+               return config->machine_password;
+       }
+
        *len = config->password_len;
        if (hash)
                *hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH);
index 148c9066d27c7e8e0d6ba7d4a0d2f24b172872be..c2f1ca0d6b80cbfa3528a88ac4fc13912f7d4921 100644 (file)
@@ -49,6 +49,20 @@ struct eap_peer_config {
        u8 *imsi_identity;
        size_t imsi_identity_len;
 
+       /**
+        * machine_identity - EAP Identity for machine credential
+        *
+        * This field is used to set the machine identity or NAI for cases where
+        * and explicit machine credential (instead of or in addition to a user
+        * credential (from %identity) is needed.
+        */
+       u8 *machine_identity;
+
+       /**
+        * machine_identity_len - EAP Identity length for machine credential
+        */
+       size_t machine_identity_len;
+
        /**
         * password - Password string for EAP
         *
@@ -72,6 +86,20 @@ struct eap_peer_config {
         */
        size_t password_len;
 
+       /**
+        * machine_password - Password string for EAP machine credential
+        *
+        * This field is used when machine credential based on username/password
+        * is needed instead of a user credential (from %password). See
+        * %password for more details on the format.
+        */
+       u8 *machine_password;
+
+       /**
+        * machine_password_len - Length of machine credential password field
+        */
+       size_t machine_password_len;
+
        /**
         * ca_cert - File path to CA certificate file (PEM/DER)
         *
@@ -751,6 +779,8 @@ struct eap_peer_config {
 
 #define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0)
 #define EAP_CONFIG_FLAGS_EXT_PASSWORD BIT(1)
+#define EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH BIT(2)
+#define EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD BIT(3)
        /**
         * flags - Network configuration flags (bitfield)
         *
@@ -760,6 +790,10 @@ struct eap_peer_config {
         *         instead of plaintext password
         * bit 1 = password is stored in external storage; the value in the
         *         password field is the name of that external entry
+        * bit 2 = machine password is represented as a 16-byte NtPasswordHash
+        *         value instead of plaintext password
+        * bit 3 = machine password is stored in external storage; the value in
+        *         the password field is the name of that external entry
         */
        u32 flags;
 
index 7c633236c6ccc1a0475495965eb8387d525e9d83..8f29d4a2623238dc3163fdf60067b8f5c86d6a3a 100644 (file)
@@ -382,6 +382,7 @@ struct eap_sm {
        unsigned int expected_failure:1;
        unsigned int ext_cert_check:1;
        unsigned int waiting_ext_cert_check:1;
+       unsigned int use_machine_cred:1;
 
        struct dl_list erp_keys; /* struct eap_erp_key */
 };
index fc1ed4f9047c9320227ddf8d612bf36707554f72..cde1e8d352383bcb4652fda82df5dace8267d54b 100644 (file)
@@ -1614,7 +1614,7 @@ static int wpa_config_parse_password(const struct parse_data *data,
 #ifdef CONFIG_EXT_PASSWORD
        if (os_strncmp(value, "ext:", 4) == 0) {
                char *name = os_strdup(value + 4);
-               if (name == NULL)
+               if (!name)
                        return -1;
                bin_clear_free(ssid->eap.password, ssid->eap.password_len);
                ssid->eap.password = (u8 *) name;
@@ -1630,9 +1630,9 @@ static int wpa_config_parse_password(const struct parse_data *data,
                size_t res_len;
 
                tmp = wpa_config_parse_string(value, &res_len);
-               if (tmp == NULL) {
-                       wpa_printf(MSG_ERROR, "Line %d: failed to parse "
-                                  "password.", line);
+               if (!tmp) {
+                       wpa_printf(MSG_ERROR,
+                                  "Line %d: failed to parse password.", line);
                        return -1;
                }
                wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
@@ -1650,13 +1650,14 @@ static int wpa_config_parse_password(const struct parse_data *data,
 
        /* NtPasswordHash: hash:<32 hex digits> */
        if (os_strlen(value + 5) != 2 * 16) {
-               wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length "
-                          "(expected 32 hex digits)", line);
+               wpa_printf(MSG_ERROR,
+                          "Line %d: Invalid password hash length (expected 32 hex digits)",
+                          line);
                return -1;
        }
 
        hash = os_malloc(16);
-       if (hash == NULL)
+       if (!hash)
                return -1;
 
        if (hexstr2bin(value + 5, hash, 16)) {
@@ -1683,19 +1684,118 @@ static int wpa_config_parse_password(const struct parse_data *data,
 }
 
 
+static int wpa_config_parse_machine_password(const struct parse_data *data,
+                                            struct wpa_ssid *ssid, int line,
+                                            const char *value)
+{
+       u8 *hash;
+
+       if (os_strcmp(value, "NULL") == 0) {
+               if (!ssid->eap.machine_password)
+                       return 1; /* Already unset */
+               wpa_printf(MSG_DEBUG,
+                          "Unset configuration string 'machine_password'");
+               bin_clear_free(ssid->eap.machine_password,
+                              ssid->eap.machine_password_len);
+               ssid->eap.machine_password = NULL;
+               ssid->eap.machine_password_len = 0;
+               return 0;
+       }
+
+#ifdef CONFIG_EXT_PASSWORD
+       if (os_strncmp(value, "ext:", 4) == 0) {
+               char *name = os_strdup(value + 4);
+
+               if (!name)
+                       return -1;
+               bin_clear_free(ssid->eap.machine_password,
+                              ssid->eap.machine_password_len);
+               ssid->eap.machine_password = (u8 *) name;
+               ssid->eap.machine_password_len = os_strlen(name);
+               ssid->eap.flags &= ~EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
+               ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
+               return 0;
+       }
+#endif /* CONFIG_EXT_PASSWORD */
+
+       if (os_strncmp(value, "hash:", 5) != 0) {
+               char *tmp;
+               size_t res_len;
+
+               tmp = wpa_config_parse_string(value, &res_len);
+               if (!tmp) {
+                       wpa_printf(MSG_ERROR,
+                                  "Line %d: failed to parse machine_password.",
+                                  line);
+                       return -1;
+               }
+               wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
+                                     (u8 *) tmp, res_len);
+
+               bin_clear_free(ssid->eap.machine_password,
+                              ssid->eap.machine_password_len);
+               ssid->eap.machine_password = (u8 *) tmp;
+               ssid->eap.machine_password_len = res_len;
+               ssid->eap.flags &= ~EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
+               ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
+
+               return 0;
+       }
+
+
+       /* NtPasswordHash: hash:<32 hex digits> */
+       if (os_strlen(value + 5) != 2 * 16) {
+               wpa_printf(MSG_ERROR,
+                          "Line %d: Invalid machine_password hash length (expected 32 hex digits)",
+                          line);
+               return -1;
+       }
+
+       hash = os_malloc(16);
+       if (!hash)
+               return -1;
+
+       if (hexstr2bin(value + 5, hash, 16)) {
+               os_free(hash);
+               wpa_printf(MSG_ERROR, "Line %d: Invalid machine_password hash",
+                          line);
+               return -1;
+       }
+
+       wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
+
+       if (ssid->eap.machine_password &&
+           ssid->eap.machine_password_len == 16 &&
+           os_memcmp(ssid->eap.machine_password, hash, 16) == 0 &&
+           (ssid->eap.flags & EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH)) {
+               bin_clear_free(hash, 16);
+               return 1;
+       }
+       bin_clear_free(ssid->eap.machine_password,
+                      ssid->eap.machine_password_len);
+       ssid->eap.machine_password = hash;
+       ssid->eap.machine_password_len = 16;
+       ssid->eap.flags |= EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH;
+       ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD;
+
+       return 0;
+}
+
+
 #ifndef NO_CONFIG_WRITE
+
 static char * wpa_config_write_password(const struct parse_data *data,
                                        struct wpa_ssid *ssid)
 {
        char *buf;
 
-       if (ssid->eap.password == NULL)
+       if (!ssid->eap.password)
                return NULL;
 
 #ifdef CONFIG_EXT_PASSWORD
        if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
                buf = os_zalloc(4 + ssid->eap.password_len + 1);
-               if (buf == NULL)
+               if (!buf)
                        return NULL;
                os_memcpy(buf, "ext:", 4);
                os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len);
@@ -1709,7 +1809,7 @@ static char * wpa_config_write_password(const struct parse_data *data,
        }
 
        buf = os_malloc(5 + 32 + 1);
-       if (buf == NULL)
+       if (!buf)
                return NULL;
 
        os_memcpy(buf, "hash:", 5);
@@ -1717,6 +1817,44 @@ static char * wpa_config_write_password(const struct parse_data *data,
 
        return buf;
 }
+
+
+static char * wpa_config_write_machine_password(const struct parse_data *data,
+                                               struct wpa_ssid *ssid)
+{
+       char *buf;
+
+       if (!ssid->eap.machine_password)
+               return NULL;
+
+#ifdef CONFIG_EXT_PASSWORD
+       if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_MACHINE_PASSWORD) {
+               buf = os_zalloc(4 + ssid->eap.machine_password_len + 1);
+               if (!buf)
+                       return NULL;
+               os_memcpy(buf, "ext:", 4);
+               os_memcpy(buf + 4, ssid->eap.machine_password,
+                         ssid->eap.machine_password_len);
+               return buf;
+       }
+#endif /* CONFIG_EXT_PASSWORD */
+
+       if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_MACHINE_PASSWORD_NTHASH)) {
+               return wpa_config_write_string(
+                       ssid->eap.machine_password,
+                       ssid->eap.machine_password_len);
+       }
+
+       buf = os_malloc(5 + 32 + 1);
+       if (!buf)
+               return NULL;
+
+       os_memcpy(buf, "hash:", 5);
+       wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.machine_password, 16);
+
+       return buf;
+}
+
 #endif /* NO_CONFIG_WRITE */
 #endif /* IEEE8021X_EAPOL */
 
@@ -2249,7 +2387,9 @@ static const struct parse_data ssid_fields[] = {
        { STR_LENe(identity) },
        { STR_LENe(anonymous_identity) },
        { STR_LENe(imsi_identity) },
+       { STR_LENe(machine_identity) },
        { FUNC_KEY(password) },
+       { FUNC_KEY(machine_password) },
        { STRe(ca_cert) },
        { STRe(ca_path) },
        { STRe(client_cert) },
@@ -2520,7 +2660,9 @@ static void eap_peer_config_free(struct eap_peer_config *eap)
        bin_clear_free(eap->identity, eap->identity_len);
        os_free(eap->anonymous_identity);
        os_free(eap->imsi_identity);
+       os_free(eap->machine_identity);
        bin_clear_free(eap->password, eap->password_len);
+       bin_clear_free(eap->machine_password, eap->machine_password_len);
        os_free(eap->ca_cert);
        os_free(eap->ca_path);
        os_free(eap->client_cert);
index 91d5caa3f2ed86a0f89619570c8f26366ff448e8..8d81e361d486cb398291e9f8a79afbb81b65ce30 100644 (file)
@@ -774,7 +774,9 @@ static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
        STR(identity);
        STR(anonymous_identity);
        STR(imsi_identity);
+       STR(machine_identity);
        STR(password);
+       STR(machine_password);
        STR(ca_cert);
        STR(ca_path);
        STR(client_cert);