|
@@ -9,6 +9,7 @@
|
|
|
#include "utils/includes.h"
|
|
#include "utils/includes.h"
|
|
|
|
|
|
|
|
#include "utils/common.h"
|
|
#include "utils/common.h"
|
|
|
|
|
+#include "crypto/md5.h"
|
|
|
#include "crypto/sha1.h"
|
|
#include "crypto/sha1.h"
|
|
|
#include "crypto/sha256.h"
|
|
#include "crypto/sha256.h"
|
|
|
#include "tls/tls.h"
|
|
#include "tls/tls.h"
|
|
@@ -333,3 +334,184 @@ int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
|
|
|
return tls_prf_sha1_md5(secret, secret_len, label, seed, seed_len, out,
|
|
return tls_prf_sha1_md5(secret, secret_len, label, seed, seed_len, out,
|
|
|
outlen);
|
|
outlen);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+#ifdef CONFIG_TLSV12
|
|
|
|
|
+int tlsv12_key_x_server_params_hash(u16 tls_version, u8 hash_alg,
|
|
|
|
|
+ const u8 *client_random,
|
|
|
|
|
+ const u8 *server_random,
|
|
|
|
|
+ const u8 *server_params,
|
|
|
|
|
+ size_t server_params_len, u8 *hash)
|
|
|
|
|
+{
|
|
|
|
|
+ size_t hlen;
|
|
|
|
|
+ struct crypto_hash *ctx;
|
|
|
|
|
+ enum crypto_hash_alg alg;
|
|
|
|
|
+
|
|
|
|
|
+ switch (hash_alg) {
|
|
|
|
|
+ case TLS_HASH_ALG_SHA256:
|
|
|
|
|
+ alg = CRYPTO_HASH_ALG_SHA256;
|
|
|
|
|
+ hlen = SHA256_MAC_LEN;
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ ctx = crypto_hash_init(alg, NULL, 0);
|
|
|
|
|
+ if (ctx == NULL)
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
|
|
|
|
|
+ crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
|
|
|
|
|
+ crypto_hash_update(ctx, server_params, server_params_len);
|
|
|
|
|
+ if (crypto_hash_finish(ctx, hash, &hlen) < 0)
|
|
|
|
|
+ return -1;
|
|
|
|
|
+
|
|
|
|
|
+ return hlen;
|
|
|
|
|
+}
|
|
|
|
|
+#endif /* CONFIG_TLSV12 */
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+int tls_key_x_server_params_hash(u16 tls_version, const u8 *client_random,
|
|
|
|
|
+ const u8 *server_random,
|
|
|
|
|
+ const u8 *server_params,
|
|
|
|
|
+ size_t server_params_len, u8 *hash)
|
|
|
|
|
+{
|
|
|
|
|
+ u8 *hpos;
|
|
|
|
|
+ size_t hlen;
|
|
|
|
|
+ struct crypto_hash *ctx;
|
|
|
|
|
+
|
|
|
|
|
+ hpos = hash;
|
|
|
|
|
+
|
|
|
|
|
+ ctx = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
|
|
|
|
|
+ if (ctx == NULL)
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
|
|
|
|
|
+ crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
|
|
|
|
|
+ crypto_hash_update(ctx, server_params, server_params_len);
|
|
|
|
|
+ hlen = MD5_MAC_LEN;
|
|
|
|
|
+ if (crypto_hash_finish(ctx, hash, &hlen) < 0)
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ hpos += hlen;
|
|
|
|
|
+
|
|
|
|
|
+ ctx = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
|
|
|
|
|
+ if (ctx == NULL)
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ crypto_hash_update(ctx, client_random, TLS_RANDOM_LEN);
|
|
|
|
|
+ crypto_hash_update(ctx, server_random, TLS_RANDOM_LEN);
|
|
|
|
|
+ crypto_hash_update(ctx, server_params, server_params_len);
|
|
|
|
|
+ hlen = hash + sizeof(hash) - hpos;
|
|
|
|
|
+ if (crypto_hash_finish(ctx, hpos, &hlen) < 0)
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ hpos += hlen;
|
|
|
|
|
+ return hpos - hash;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+int tls_verify_signature(u16 tls_version, struct crypto_public_key *pk,
|
|
|
|
|
+ const u8 *data, size_t data_len,
|
|
|
|
|
+ const u8 *pos, size_t len, u8 *alert)
|
|
|
|
|
+{
|
|
|
|
|
+ u8 *buf;
|
|
|
|
|
+ const u8 *end = pos + len;
|
|
|
|
|
+ const u8 *decrypted;
|
|
|
|
|
+ u16 slen;
|
|
|
|
|
+ size_t buflen;
|
|
|
|
|
+
|
|
|
|
|
+ if (end - pos < 2) {
|
|
|
|
|
+ *alert = TLS_ALERT_DECODE_ERROR;
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ slen = WPA_GET_BE16(pos);
|
|
|
|
|
+ pos += 2;
|
|
|
|
|
+ if (end - pos < slen) {
|
|
|
|
|
+ *alert = TLS_ALERT_DECODE_ERROR;
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (end - pos > slen) {
|
|
|
|
|
+ wpa_hexdump(MSG_MSGDUMP, "Additional data after Signature",
|
|
|
|
|
+ pos + slen, end - pos - slen);
|
|
|
|
|
+ end = pos + slen;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ wpa_hexdump(MSG_MSGDUMP, "TLSv1: Signature", pos, end - pos);
|
|
|
|
|
+ if (pk == NULL) {
|
|
|
|
|
+ wpa_printf(MSG_DEBUG, "TLSv1: No public key to verify signature");
|
|
|
|
|
+ *alert = TLS_ALERT_INTERNAL_ERROR;
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ buflen = end - pos;
|
|
|
|
|
+ buf = os_malloc(end - pos);
|
|
|
|
|
+ if (buf == NULL) {
|
|
|
|
|
+ *alert = TLS_ALERT_INTERNAL_ERROR;
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ if (crypto_public_key_decrypt_pkcs1(pk, pos, end - pos, buf, &buflen) <
|
|
|
|
|
+ 0) {
|
|
|
|
|
+ wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt signature");
|
|
|
|
|
+ os_free(buf);
|
|
|
|
|
+ *alert = TLS_ALERT_DECRYPT_ERROR;
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ decrypted = buf;
|
|
|
|
|
+
|
|
|
|
|
+ wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
|
|
|
|
|
+ decrypted, buflen);
|
|
|
|
|
+
|
|
|
|
|
+#ifdef CONFIG_TLSV12
|
|
|
|
|
+ if (tls_version >= TLS_VERSION_1_2) {
|
|
|
|
|
+ /*
|
|
|
|
|
+ * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
|
|
|
|
|
+ *
|
|
|
|
|
+ * DigestInfo ::= SEQUENCE {
|
|
|
|
|
+ * digestAlgorithm DigestAlgorithm,
|
|
|
|
|
+ * digest OCTET STRING
|
|
|
|
|
+ * }
|
|
|
|
|
+ *
|
|
|
|
|
+ * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
|
|
|
|
|
+ *
|
|
|
|
|
+ * DER encoded DigestInfo for SHA256 per RFC 3447:
|
|
|
|
|
+ * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
|
|
|
|
|
+ * H
|
|
|
|
|
+ */
|
|
|
|
|
+ if (buflen >= 19 + 32 &&
|
|
|
|
|
+ os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
|
|
|
|
|
+ "\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithm = SHA-256");
|
|
|
|
|
+ decrypted = buf + 19;
|
|
|
|
|
+ buflen -= 19;
|
|
|
|
|
+ } else if (buflen >= 19 + 48 &&
|
|
|
|
|
+ os_memcmp(buf, "\x30\x41\x30\x0d\x06\x09\x60\x86\x48\x01"
|
|
|
|
|
+ "\x65\x03\x04\x02\x02\x05\x00\x04\x30", 19) == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithm = SHA-384");
|
|
|
|
|
+ decrypted = buf + 19;
|
|
|
|
|
+ buflen -= 19;
|
|
|
|
|
+ } else if (buflen >= 19 + 64 &&
|
|
|
|
|
+ os_memcmp(buf, "\x30\x51\x30\x0d\x06\x09\x60\x86\x48\x01"
|
|
|
|
|
+ "\x65\x03\x04\x02\x03\x05\x00\x04\x40", 19) == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithm = SHA-512");
|
|
|
|
|
+ decrypted = buf + 19;
|
|
|
|
|
+ buflen -= 19;
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+ wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized DigestInfo");
|
|
|
|
|
+ os_free(buf);
|
|
|
|
|
+ *alert = TLS_ALERT_DECRYPT_ERROR;
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+#endif /* CONFIG_TLSV12 */
|
|
|
|
|
+
|
|
|
|
|
+ if (buflen != data_len ||
|
|
|
|
|
+ os_memcmp_const(decrypted, data, data_len) != 0) {
|
|
|
|
|
+ wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in CertificateVerify - did not match calculated hash");
|
|
|
|
|
+ os_free(buf);
|
|
|
|
|
+ *alert = TLS_ALERT_DECRYPT_ERROR;
|
|
|
|
|
+ return -1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ os_free(buf);
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+}
|