From b3ddab21223455c147bb18334745eddc5773b487 Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Thu, 22 Jan 2009 19:32:58 +0200 Subject: [PATCH] WPS: Pad DH Public Key and Shared Key to 192 octets WPS spec is not very specific on the presentation used for the DH values. The Public Key attribute is described to be 192 octets long, so that could be interpreted to imply that other places use fixed length presentation for the DH keys. Change the DH derivation to use fixed length bufferd by zero padding them from beginning if needed. This can resolve infrequent (about 1/256 chance for both Public Key and Shared Key being shorter) interop issues. --- src/utils/wpabuf.c | 35 +++++++++++++++++++++++++++++++++++ src/utils/wpabuf.h | 1 + src/wps/wps_attr_build.c | 1 + src/wps/wps_common.c | 1 + 4 files changed, 38 insertions(+) diff --git a/src/utils/wpabuf.c b/src/utils/wpabuf.c index 3719aaeed..e809690b9 100644 --- a/src/utils/wpabuf.c +++ b/src/utils/wpabuf.c @@ -160,3 +160,38 @@ struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b) return n; } + + +/** + * wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length + * @buf: Buffer to be padded + * @len: Length for the padded buffer + * Returns: wpabuf padded to len octets or %NULL on failure + * + * If buf is longer than len octets or of same size, it will be returned as-is. + * Otherwise a new buffer is allocated and prefixed with 0x00 octets followed + * by the source data. The source buffer will be freed on error, i.e., caller + * will only be responsible on freeing the returned buffer. If buf is %NULL, + * %NULL will be returned. + */ +struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len) +{ + struct wpabuf *ret; + size_t blen; + + if (buf == NULL) + return NULL; + + blen = wpabuf_len(buf); + if (blen >= len) + return buf; + + ret = wpabuf_alloc(len); + if (ret) { + os_memset(wpabuf_put(ret, len - blen), 0, len - blen); + wpabuf_put_buf(ret, buf); + } + wpabuf_free(buf); + + return ret; +} diff --git a/src/utils/wpabuf.h b/src/utils/wpabuf.h index 724412e31..5d435ab10 100644 --- a/src/utils/wpabuf.h +++ b/src/utils/wpabuf.h @@ -37,6 +37,7 @@ struct wpabuf * wpabuf_dup(const struct wpabuf *src); void wpabuf_free(struct wpabuf *buf); void * wpabuf_put(struct wpabuf *buf, size_t len); struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b); +struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len); /** diff --git a/src/wps/wps_attr_build.c b/src/wps/wps_attr_build.c index c30e17b3d..edeff5c58 100644 --- a/src/wps/wps_attr_build.c +++ b/src/wps/wps_attr_build.c @@ -27,6 +27,7 @@ int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg) wpa_printf(MSG_DEBUG, "WPS: * Public Key"); pubkey = dh_init(dh_groups_get(WPS_DH_GROUP), &wps->dh_privkey); + pubkey = wpabuf_zeropad(pubkey, 192); if (pubkey == NULL) { wpa_printf(MSG_DEBUG, "WPS: Failed to initialize " "Diffie-Hellman handshake"); diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c index 9273d3749..050f04305 100644 --- a/src/wps/wps_common.c +++ b/src/wps/wps_common.c @@ -82,6 +82,7 @@ int wps_derive_keys(struct wps_data *wps) dh_shared = dh_derive_shared(pubkey, wps->dh_privkey, dh_groups_get(WPS_DH_GROUP)); + dh_shared = wpabuf_zeropad(dh_shared, 192); if (dh_shared == NULL) { wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key"); return -1;