diff options
| author | Dmitry Shmidt <dimitrysh@google.com> | 2014-05-21 14:01:45 -0700 |
|---|---|---|
| committer | Dmitry Shmidt <dimitrysh@google.com> | 2014-05-21 14:01:45 -0700 |
| commit | 50b691dc36a8075e8f594e8bea93cb524fa6b1d2 (patch) | |
| tree | 9bfa2c196f72862429ac66a34f43c23d1fc570f0 /src/tls | |
| parent | 6dc03bd757d3befd2c03a543a402338db03914d6 (diff) | |
| download | android_external_wpa_supplicant_8-50b691dc36a8075e8f594e8bea93cb524fa6b1d2.tar.gz android_external_wpa_supplicant_8-50b691dc36a8075e8f594e8bea93cb524fa6b1d2.tar.bz2 android_external_wpa_supplicant_8-50b691dc36a8075e8f594e8bea93cb524fa6b1d2.zip | |
Cumulative patch from commit 54ac6ff8c4a20f8c3678e0c610716ce7795b8320
54ac6ff PKCS 1: Add function for checking v1.5 RSA signature
d381184 RSA: Add OID definitions and helper function for hash algorithms
ab6d047 Add function for building RSA public key from n and e parameters
6c5be11 PKCS #1: Enforce minimum padding for decryption in internal TLS
e6d83cc PKCS #1: Allow only BT=01 for signature in internal TLS
9c29d48 X.509: Fix internal TLS/X.509 validation of PKCS#1 signature
10b58b5 TNC: Allow TNC to be enabled dynamically
0a626a5 TNC: Move common definitions into a shared header file
4075e4e TNC: Allow tnc_config file path to be replaced
f0356ec eloop: Add epoll option for better performance
da96a6f eloop: Separate event loop select/poll implementation
68d2700 dbus: No need to recompute group object path on GroupStarted signal
f3734e2 dbus: Provide the P2P Device Address from the relevant structure
e956b83 dbus: Fix interface DeviceFound signal specification
fc591a7 dbus: Declare GONegotiation signals properly
Change-Id: I54a598ae249ca569f15eaef8f728985897e1b2f0
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
Diffstat (limited to 'src/tls')
| -rw-r--r-- | src/tls/asn1.c | 31 | ||||
| -rw-r--r-- | src/tls/asn1.h | 6 | ||||
| -rw-r--r-- | src/tls/pkcs1.c | 165 | ||||
| -rw-r--r-- | src/tls/pkcs1.h | 7 | ||||
| -rw-r--r-- | src/tls/rsa.c | 25 | ||||
| -rw-r--r-- | src/tls/rsa.h | 3 | ||||
| -rw-r--r-- | src/tls/x509v3.c | 9 |
7 files changed, 222 insertions, 24 deletions
diff --git a/src/tls/asn1.c b/src/tls/asn1.c index 53acd530..97462fac 100644 --- a/src/tls/asn1.c +++ b/src/tls/asn1.c @@ -1,6 +1,6 @@ /* * ASN.1 DER parsing - * Copyright (c) 2006, Jouni Malinen <j@w1.fi> + * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -11,6 +11,17 @@ #include "common.h" #include "asn1.h" +struct asn1_oid asn1_sha1_oid = { + .oid = { 1, 3, 14, 3, 2, 26 }, + .len = 6 +}; + +struct asn1_oid asn1_sha256_oid = { + .oid = { 2, 16, 840, 1, 101, 3, 4, 2, 1 }, + .len = 9 +}; + + int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr) { const u8 *pos, *end; @@ -140,7 +151,7 @@ int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, } -void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len) +void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len) { char *pos = buf; size_t i; @@ -204,3 +215,19 @@ unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len) return val; } + + +int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b) +{ + size_t i; + + if (a->len != b->len) + return 0; + + for (i = 0; i < a->len; i++) { + if (a->oid[i] != b->oid[i]) + return 0; + } + + return 1; +} diff --git a/src/tls/asn1.h b/src/tls/asn1.h index 6342c4cc..74750076 100644 --- a/src/tls/asn1.h +++ b/src/tls/asn1.h @@ -60,7 +60,11 @@ int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr); int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid); int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid, const u8 **next); -void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len); +void asn1_oid_to_str(const struct asn1_oid *oid, char *buf, size_t len); unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len); +int asn1_oid_equal(const struct asn1_oid *a, const struct asn1_oid *b); + +extern struct asn1_oid asn1_sha1_oid; +extern struct asn1_oid asn1_sha256_oid; #endif /* ASN1_H */ diff --git a/src/tls/pkcs1.c b/src/tls/pkcs1.c index b6fde5ee..381b7a03 100644 --- a/src/tls/pkcs1.c +++ b/src/tls/pkcs1.c @@ -1,6 +1,6 @@ /* * PKCS #1 (RSA Encryption) - * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi> + * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -9,7 +9,9 @@ #include "includes.h" #include "common.h" +#include "crypto/crypto.h" #include "rsa.h" +#include "asn1.h" #include "pkcs1.h" @@ -113,6 +115,11 @@ int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key, pos++; if (pos == end) return -1; + if (pos - out - 2 < 8) { + /* PKCS #1 v1.5, 8.1: At least eight octets long PS */ + wpa_printf(MSG_INFO, "LibTomCrypt: Too short padding"); + return -1; + } pos++; *outlen -= pos - out; @@ -142,35 +149,26 @@ int pkcs1_decrypt_public_key(struct crypto_rsa_key *key, * BT = 00 or 01 * PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01) * k = length of modulus in octets + * + * Based on 10.1.3, "The block type shall be 01" for a signature. */ if (len < 3 + 8 + 16 /* min hash len */ || - plain[0] != 0x00 || (plain[1] != 0x00 && plain[1] != 0x01)) { + plain[0] != 0x00 || plain[1] != 0x01) { wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB " "structure"); return -1; } pos = plain + 3; - if (plain[1] == 0x00) { - /* BT = 00 */ - if (plain[2] != 0x00) { - wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature " - "PS (BT=00)"); - return -1; - } - while (pos + 1 < plain + len && *pos == 0x00 && pos[1] == 0x00) - pos++; - } else { - /* BT = 01 */ - if (plain[2] != 0xff) { - wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature " - "PS (BT=01)"); - return -1; - } - while (pos < plain + len && *pos == 0xff) - pos++; + /* BT = 01 */ + if (plain[2] != 0xff) { + wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature " + "PS (BT=01)"); + return -1; } + while (pos < plain + len && *pos == 0xff) + pos++; if (pos - plain - 2 < 8) { /* PKCS #1 v1.5, 8.1: At least eight octets long PS */ @@ -193,3 +191,130 @@ int pkcs1_decrypt_public_key(struct crypto_rsa_key *key, return 0; } + + +int pkcs1_v15_sig_ver(struct crypto_public_key *pk, + const u8 *s, size_t s_len, + const struct asn1_oid *hash_alg, + const u8 *hash, size_t hash_len) +{ + int res; + u8 *decrypted; + size_t decrypted_len; + const u8 *pos, *end, *next, *da_end; + struct asn1_hdr hdr; + struct asn1_oid oid; + + decrypted = os_malloc(s_len); + if (decrypted == NULL) + return -1; + decrypted_len = s_len; + res = crypto_public_key_decrypt_pkcs1(pk, s, s_len, decrypted, + &decrypted_len); + if (res < 0) { + wpa_printf(MSG_INFO, "PKCS #1: RSA decrypt failed"); + os_free(decrypted); + return -1; + } + wpa_hexdump(MSG_DEBUG, "Decrypted(S)", decrypted, decrypted_len); + + /* + * PKCS #1 v1.5, 10.1.2: + * + * DigestInfo ::= SEQUENCE { + * digestAlgorithm DigestAlgorithmIdentifier, + * digest Digest + * } + * + * DigestAlgorithmIdentifier ::= AlgorithmIdentifier + * + * Digest ::= OCTET STRING + * + */ + if (asn1_get_next(decrypted, decrypted_len, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, + "PKCS #1: Expected SEQUENCE (DigestInfo) - found class %d tag 0x%x", + hdr.class, hdr.tag); + os_free(decrypted); + return -1; + } + + pos = hdr.payload; + end = pos + hdr.length; + + /* + * X.509: + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + */ + + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_SEQUENCE) { + wpa_printf(MSG_DEBUG, + "PKCS #1: Expected SEQUENCE (AlgorithmIdentifier) - found class %d tag 0x%x", + hdr.class, hdr.tag); + os_free(decrypted); + return -1; + } + da_end = hdr.payload + hdr.length; + + if (asn1_get_oid(hdr.payload, hdr.length, &oid, &next)) { + wpa_printf(MSG_DEBUG, + "PKCS #1: Failed to parse digestAlgorithm"); + os_free(decrypted); + return -1; + } + + if (!asn1_oid_equal(&oid, hash_alg)) { + char txt[100], txt2[100]; + asn1_oid_to_str(&oid, txt, sizeof(txt)); + asn1_oid_to_str(hash_alg, txt2, sizeof(txt2)); + wpa_printf(MSG_DEBUG, + "PKCS #1: Hash alg OID mismatch: was %s, expected %s", + txt, txt2); + os_free(decrypted); + return -1; + } + + /* Digest ::= OCTET STRING */ + pos = da_end; + end = decrypted + decrypted_len; + + if (asn1_get_next(pos, end - pos, &hdr) < 0 || + hdr.class != ASN1_CLASS_UNIVERSAL || + hdr.tag != ASN1_TAG_OCTETSTRING) { + wpa_printf(MSG_DEBUG, + "PKCS #1: Expected OCTETSTRING (Digest) - found class %d tag 0x%x", + hdr.class, hdr.tag); + os_free(decrypted); + return -1; + } + wpa_hexdump(MSG_MSGDUMP, "PKCS #1: Decrypted Digest", + hdr.payload, hdr.length); + + if (hdr.length != hash_len || + os_memcmp(hdr.payload, hash, hdr.length) != 0) { + wpa_printf(MSG_INFO, "PKCS #1: Digest value does not match calculated hash"); + os_free(decrypted); + return -1; + } + + os_free(decrypted); + + if (hdr.payload + hdr.length != end) { + wpa_printf(MSG_INFO, + "PKCS #1: Extra data after signature - reject"); + + wpa_hexdump(MSG_DEBUG, "PKCS #1: Extra data", + hdr.payload + hdr.length, + end - hdr.payload - hdr.length); + return -1; + } + + return 0; +} diff --git a/src/tls/pkcs1.h b/src/tls/pkcs1.h index ed64defa..f37ebf38 100644 --- a/src/tls/pkcs1.h +++ b/src/tls/pkcs1.h @@ -9,6 +9,9 @@ #ifndef PKCS1_H #define PKCS1_H +struct crypto_public_key; +struct asn1_oid; + int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key, int use_private, const u8 *in, size_t inlen, u8 *out, size_t *outlen); @@ -18,5 +21,9 @@ int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key, int pkcs1_decrypt_public_key(struct crypto_rsa_key *key, const u8 *crypt, size_t crypt_len, u8 *plain, size_t *plain_len); +int pkcs1_v15_sig_ver(struct crypto_public_key *pk, + const u8 *s, size_t s_len, + const struct asn1_oid *hash_alg, + const u8 *hash, size_t hash_len); #endif /* PKCS1_H */ diff --git a/src/tls/rsa.c b/src/tls/rsa.c index 125c4205..0b7b530b 100644 --- a/src/tls/rsa.c +++ b/src/tls/rsa.c @@ -1,6 +1,6 @@ /* * RSA - * Copyright (c) 2006, Jouni Malinen <j@w1.fi> + * Copyright (c) 2006-2014, Jouni Malinen <j@w1.fi> * * This software may be distributed under the terms of the BSD license. * See README for more details. @@ -116,6 +116,29 @@ error: } +struct crypto_rsa_key * +crypto_rsa_import_public_key_parts(const u8 *n, size_t n_len, + const u8 *e, size_t e_len) +{ + struct crypto_rsa_key *key; + + key = os_zalloc(sizeof(*key)); + if (key == NULL) + return NULL; + + key->n = bignum_init(); + key->e = bignum_init(); + if (key->n == NULL || key->e == NULL || + bignum_set_unsigned_bin(key->n, n, n_len) < 0 || + bignum_set_unsigned_bin(key->e, e, e_len) < 0) { + crypto_rsa_free(key); + return NULL; + } + + return key; +} + + /** * crypto_rsa_import_private_key - Import an RSA private key * @buf: Key buffer (DER encoded RSA private key) diff --git a/src/tls/rsa.h b/src/tls/rsa.h index c236a9df..b65818ee 100644 --- a/src/tls/rsa.h +++ b/src/tls/rsa.h @@ -14,6 +14,9 @@ struct crypto_rsa_key; struct crypto_rsa_key * crypto_rsa_import_public_key(const u8 *buf, size_t len); struct crypto_rsa_key * +crypto_rsa_import_public_key_parts(const u8 *n, size_t n_len, + const u8 *e, size_t e_len); +struct crypto_rsa_key * crypto_rsa_import_private_key(const u8 *buf, size_t len); size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key); int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen, diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c index a9483cb7..751a268e 100644 --- a/src/tls/x509v3.c +++ b/src/tls/x509v3.c @@ -1783,6 +1783,15 @@ skip_digest_oid: return -1; } + if (hdr.payload + hdr.length < data + data_len) { + wpa_hexdump(MSG_INFO, + "X509: Extra data after certificate signature hash", + hdr.payload + hdr.length, + data + data_len - hdr.payload - hdr.length); + os_free(data); + return -1; + } + os_free(data); wpa_printf(MSG_DEBUG, "X509: Certificate Digest matches with " |
