| #include <stdint.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <stddef.h> |
| #include <stdarg.h> |
| #include "picotls.h" |
| #include "picotls/asn1.h" |
| #include "picotls/minicrypto.h" |
| |
| static struct feeder { |
| const uint8_t *data; |
| size_t size; |
| } feeder; |
| |
| static void feeder_init(const uint8_t *orig_data, size_t orig_size) |
| { |
| feeder.data = orig_data; |
| feeder.size = orig_size; |
| } |
| |
| static uint8_t feeder_next_byte(void) |
| { |
| if (feeder.size == 0) { |
| return 0; |
| } |
| uint8_t byte = *feeder.data; |
| --feeder.size; |
| ++feeder.data; |
| return byte; |
| } |
| |
| void count_printf(void *ctx, const char *format, ...) |
| { |
| int *c = ctx; |
| c++; |
| return; |
| } |
| |
| int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) |
| { |
| int i, counter, indefinite_length, decode_error; |
| ptls_minicrypto_log_ctx_t ctx = {&counter, count_printf}; |
| uint8_t *bytes, expected_type; |
| size_t last_byte, bytes_max, byte_index; |
| uint32_t length; |
| uint8_t ret; |
| |
| feeder_init(Data, Size); |
| |
| bytes_max = (feeder_next_byte() << 8) + feeder_next_byte(); |
| if (bytes_max == 0) |
| return 0; |
| |
| /* fill the test buffer */ |
| bytes = malloc(bytes_max); |
| for (i = 0; i < bytes_max; i++) { |
| bytes[i] = feeder_next_byte(); |
| } |
| |
| ret = feeder_next_byte() % 4; |
| /* fuzz either ptls_asn1_validation or ptls_asn1_get_expected_type_and_length */ |
| if (ret == 0) { |
| ptls_asn1_validation(bytes, bytes_max, &ctx); |
| } else if (ret == 1) { |
| byte_index = (feeder_next_byte() << 8) + feeder_next_byte(); |
| byte_index = byte_index % bytes_max; |
| expected_type = feeder_next_byte(); |
| ptls_asn1_get_expected_type_and_length(bytes, bytes_max, byte_index, expected_type, &length, &indefinite_length, &last_byte, |
| &decode_error, &ctx); |
| } else if (ret == 2 || ret == 3) { |
| ptls_context_t ctx = {}; |
| char fname[] = "/tmp/XXXXXXXX"; |
| int fd, ret; |
| fd = mkstemp(fname); |
| if (fd < 0) { |
| goto out; |
| } |
| ret = write(fd, bytes, bytes_max); |
| if (ret != bytes_max) { |
| goto out2; |
| } |
| ctx.random_bytes = ptls_minicrypto_random_bytes; |
| ctx.get_time = &ptls_get_time; |
| ctx.key_exchanges = ptls_minicrypto_key_exchanges; |
| ctx.cipher_suites = ptls_minicrypto_cipher_suites; |
| |
| if (ret == 2) { |
| ptls_load_certificates(&ctx, fname); |
| if (ctx.certificates.list) { |
| for (i = 0; i < ctx.certificates.count; i++) { |
| if (ctx.certificates.list[i].base) |
| free(ctx.certificates.list[i].base); |
| } |
| free(ctx.certificates.list); |
| |
| } |
| } else { |
| ptls_minicrypto_load_private_key(&ctx, fname); |
| free(ctx.pkey_buf.base); |
| } |
| out2: |
| close(fd); |
| unlink(fname); |
| } |
| out: |
| free(bytes); |
| return 0; |
| } |