diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_library.c b/src/libstrongswan/plugins/pkcs11/pkcs11_library.c index 43da98f4f..7eff79440 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_library.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_library.c @@ -667,6 +667,32 @@ static void free_attrs(object_enumerator_t *this) } } +/** + * Make sure the type and length of an unwrapped EC_POINT is valid. + * + * We assume the smallest curve we support is prime192v1 and that the length + * of a coordinate is a multiple of 4 bytes (step from prime192v1 to secp224r1), + */ +static inline bool valid_ec_point_type_and_len(u_char type, size_t len) +{ + size_t min_len = 24, min_multiple = 4; + + switch (type) + { + case 0x04: + /* uncompressed points have two coordinates */ + min_len <<= 1; + min_multiple <<= 1; + /* fall-through */ + case 0x02: + case 0x03: + /* uncompressed points */ + return len > min_len && (len % min_multiple) == 0; + default: + return FALSE; + } +} + /** * CKA_EC_POINT is encoded as ASN.1 octet string, we can't handle that and * some tokens actually return them even unwrapped. @@ -674,21 +700,22 @@ static void free_attrs(object_enumerator_t *this) * Because ASN1_OCTET_STRING is 0x04 and uncompressed EC_POINTs also begin with * 0x04 (compressed ones with 0x02 or 0x03) there will be an attempt to parse * unwrapped uncompressed EC_POINTs. This will fail in most cases as the length - * will not be correct, however, there is a small chance that the key's first - * byte denotes the correct length. Checking the first byte of the key should - * further reduce the risk of false positives, though. + * will not be correct, however, there is a small chance that the point's first + * byte denotes the correct length. Checking the first byte of the point and + * its length should further reduce the risk of false positives, though. * * The original memory is freed if the value is unwrapped. */ static void unwrap_ec_point(chunk_t *data) { - chunk_t wrapped, unwrapped; + chunk_t wrapped, wrapper, point; - wrapped = unwrapped = *data; - if (asn1_unwrap(&unwrapped, &unwrapped) == ASN1_OCTET_STRING && - unwrapped.len && unwrapped.ptr[0] >= 0x02 && unwrapped.ptr[0] <= 0x04) + wrapped = wrapper = *data; + if (asn1_unwrap(&wrapper, &point) == ASN1_OCTET_STRING && + !wrapper.len && point.len > 1 && + valid_ec_point_type_and_len(point.ptr[0], point.len - 1)) { - *data = chunk_clone(unwrapped); + *data = chunk_clone(point); free(wrapped.ptr); } }