/* * Copyright (c) 2017 Lev Walkin . * All rights reserved. * Redistribution and modifications are permitted subject to BSD license. */ #include #include /* * Biased function for randomizing character values around their limits. */ static uint32_t OCTET_STRING__random_char(unsigned long lb, unsigned long ub) { assert(lb <= ub); switch(asn_random_between(0, 16)) { case 0: if(lb < ub) return lb + 1; /* Fall through */ case 1: return lb; case 2: if(lb < ub) return ub - 1; /* Fall through */ case 3: return ub; default: return asn_random_between(lb, ub); } } asn_random_fill_result_t OCTET_STRING_random_fill(const asn_TYPE_descriptor_t *td, void **sptr, const asn_encoding_constraints_t *constraints, size_t max_length) { const asn_OCTET_STRING_specifics_t *specs = td->specifics ? (const asn_OCTET_STRING_specifics_t *)td->specifics : &asn_SPC_OCTET_STRING_specs; asn_random_fill_result_t result_ok = {ARFILL_OK, 1}; asn_random_fill_result_t result_failed = {ARFILL_FAILED, 0}; asn_random_fill_result_t result_skipped = {ARFILL_SKIPPED, 0}; unsigned int unit_bytes = 1; unsigned long clb = 0; /* Lower bound on char */ unsigned long cub = 255; /* Higher bound on char value */ uint8_t *buf; uint8_t *bend; uint8_t *b; size_t rnd_len; OCTET_STRING_t *st; if(max_length == 0 && !*sptr) return result_skipped; switch(specs->subvariant) { default: case ASN_OSUBV_ANY: return result_failed; case ASN_OSUBV_BIT: /* Handled by BIT_STRING itself. */ return result_failed; case ASN_OSUBV_STR: unit_bytes = 1; clb = 0; cub = 255; break; case ASN_OSUBV_U16: unit_bytes = 2; clb = 0; cub = 65535; break; case ASN_OSUBV_U32: unit_bytes = 4; clb = 0; cub = 0x10FFFF; break; } #if !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT) if(!constraints || !constraints->per_constraints) constraints = &td->encoding_constraints; if(constraints->per_constraints) { const asn_per_constraint_t *pc = &constraints->per_constraints->value; if(pc->flags & APC_SEMI_CONSTRAINED) { clb = pc->lower_bound; } else if(pc->flags & APC_CONSTRAINED) { clb = pc->lower_bound; cub = pc->upper_bound; } } #else if(!constraints) constraints = &td->encoding_constraints; #endif /* !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT) */ rnd_len = OCTET_STRING_random_length_constrained(td, constraints, max_length); buf = CALLOC(unit_bytes, rnd_len + 1); if(!buf) return result_failed; bend = &buf[unit_bytes * rnd_len]; switch(unit_bytes) { case 1: for(b = buf; b < bend; b += unit_bytes) { *(uint8_t *)b = OCTET_STRING__random_char(clb, cub); } *(uint8_t *)b = 0; break; case 2: for(b = buf; b < bend; b += unit_bytes) { uint32_t code = OCTET_STRING__random_char(clb, cub); b[0] = code >> 8; b[1] = code; } *(uint16_t *)b = 0; break; case 4: for(b = buf; b < bend; b += unit_bytes) { uint32_t code = OCTET_STRING__random_char(clb, cub); b[0] = code >> 24; b[1] = code >> 16; b[2] = code >> 8; b[3] = code; } *(uint32_t *)b = 0; break; } if(*sptr) { st = *sptr; FREEMEM(st->buf); } else { st = (OCTET_STRING_t *)(*sptr = CALLOC(1, specs->struct_size)); if(!st) { FREEMEM(buf); return result_failed; } } st->buf = buf; st->size = unit_bytes * rnd_len; result_ok.length = st->size; return result_ok; } size_t OCTET_STRING_random_length_constrained( const asn_TYPE_descriptor_t *td, const asn_encoding_constraints_t *constraints, size_t max_length) { const unsigned lengths[] = {0, 1, 2, 3, 4, 8, 126, 127, 128, 16383, 16384, 16385, 65534, 65535, 65536, 65537}; size_t rnd_len; /* Figure out how far we should go */ rnd_len = lengths[asn_random_between( 0, sizeof(lengths) / sizeof(lengths[0]) - 1)]; #if !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT) if(!constraints || !constraints->per_constraints) constraints = &td->encoding_constraints; if(constraints->per_constraints) { const asn_per_constraint_t *pc = &constraints->per_constraints->size; if(pc->flags & APC_CONSTRAINED) { long suggested_upper_bound = pc->upper_bound < (ssize_t)max_length ? pc->upper_bound : (ssize_t)max_length; if(max_length <= (size_t)pc->lower_bound) { return pc->lower_bound; } if(pc->flags & APC_EXTENSIBLE) { switch(asn_random_between(0, 5)) { case 0: if(pc->lower_bound > 0) { rnd_len = pc->lower_bound - 1; break; } /* Fall through */ case 1: rnd_len = pc->upper_bound + 1; break; case 2: /* Keep rnd_len from the table */ if(rnd_len <= max_length) { break; } /* Fall through */ default: rnd_len = asn_random_between(pc->lower_bound, suggested_upper_bound); } } else { rnd_len = asn_random_between(pc->lower_bound, suggested_upper_bound); } } else { rnd_len = asn_random_between(0, max_length); } } else { #else if(!constraints) constraints = &td->encoding_constraints; { #endif /* !defined(ASN_DISABLE_UPER_SUPPORT) || !defined(ASN_DISABLE_APER_SUPPORT) */ if(rnd_len > max_length) { rnd_len = asn_random_between(0, max_length); } } return rnd_len; }