Lev Walkin | e4d8c92 | 2017-07-10 20:29:33 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>. |
| 3 | * All rights reserved. |
Lev Walkin | 086ee9a | 2017-08-08 02:05:55 -0700 | [diff] [blame] | 4 | * Redistribution and modifications are permitted subject to BSD license. |
Lev Walkin | e4d8c92 | 2017-07-10 20:29:33 -0700 | [diff] [blame] | 5 | */ |
| 6 | #include <asn_system.h> |
| 7 | #include <asn_internal.h> |
| 8 | |
| 9 | #include <oer_support.h> |
| 10 | |
| 11 | /* |
| 12 | * Fetch the length determinant (X.696 08/2015, #8.6) into *len_r. |
| 13 | * RETURN VALUES: |
| 14 | * 0: More data expected than bufptr contains. |
| 15 | * -1: Fatal error deciphering length. |
| 16 | * >0: Number of bytes used from bufptr. |
| 17 | */ |
| 18 | ssize_t |
| 19 | oer_fetch_length(const void *bufptr, size_t size, size_t *len_r) { |
| 20 | uint8_t first_byte; |
| 21 | uint8_t len_len; /* Length of the length determinant */ |
| 22 | const uint8_t *b; |
| 23 | const uint8_t *bend; |
| 24 | size_t len; |
| 25 | |
| 26 | if(size == 0) { |
| 27 | *len_r = 0; |
| 28 | return 0; |
| 29 | } |
| 30 | |
| 31 | first_byte = *(const uint8_t *)bufptr; |
| 32 | if((first_byte & 0x80) == 0) { /* Short form */ |
| 33 | *len_r = first_byte; /* 0..127 */ |
| 34 | return 1; |
| 35 | } |
| 36 | |
| 37 | len_len = (first_byte & 0x7f); |
| 38 | if((1 + len_len) > size) { |
| 39 | *len_r = 0; |
| 40 | return 0; |
| 41 | } |
| 42 | |
| 43 | b = (const uint8_t *)bufptr + 1; |
| 44 | bend = b + len_len; |
| 45 | |
| 46 | for(; b < bend && *b == 0; b++) { |
| 47 | /* Skip the leading 0-bytes */ |
| 48 | } |
| 49 | |
Lev Walkin | 494fb70 | 2017-08-07 20:07:00 -0700 | [diff] [blame] | 50 | if((bend - b) > (ssize_t)sizeof(size_t)) { |
Lev Walkin | e4d8c92 | 2017-07-10 20:29:33 -0700 | [diff] [blame] | 51 | /* Length is not representable by the native size_t type */ |
| 52 | *len_r = 0; |
| 53 | return -1; |
| 54 | } |
| 55 | |
| 56 | for(len = 0; b < bend; b++) { |
| 57 | len = (len << 8) + *b; |
| 58 | } |
| 59 | |
Lev Walkin | c6bd359 | 2017-08-30 17:36:23 -0700 | [diff] [blame] | 60 | if(len > RSIZE_MAX) { /* A bit of C11 validation */ |
| 61 | *len_r = 0; |
Lev Walkin | 39837e6 | 2017-07-20 14:51:08 +0300 | [diff] [blame] | 62 | return -1; |
Lev Walkin | c6bd359 | 2017-08-30 17:36:23 -0700 | [diff] [blame] | 63 | } |
Lev Walkin | 39837e6 | 2017-07-20 14:51:08 +0300 | [diff] [blame] | 64 | |
Lev Walkin | e4d8c92 | 2017-07-10 20:29:33 -0700 | [diff] [blame] | 65 | *len_r = len; |
| 66 | assert(len_len + 1 == bend - (const uint8_t *)bufptr); |
| 67 | return len_len + 1; |
| 68 | } |
| 69 | |
| 70 | |
Lev Walkin | fcfe19b | 2017-07-10 21:57:14 -0700 | [diff] [blame] | 71 | /* |
| 72 | * Serialize OER length. Returns the number of bytes serialized |
| 73 | * or -1 if a given callback returned with negative result. |
| 74 | */ |
| 75 | ssize_t |
| 76 | oer_serialize_length(size_t length, asn_app_consume_bytes_f *cb, |
| 77 | void *app_key) { |
| 78 | uint8_t scratch[1 + sizeof(length)]; |
| 79 | uint8_t *sp = scratch; |
| 80 | int littleEndian = 1; /* Run-time detection */ |
| 81 | const uint8_t *pstart; |
| 82 | const uint8_t *pend; |
| 83 | const uint8_t *p; |
| 84 | int add; |
| 85 | |
| 86 | if(length <= 127) { |
| 87 | uint8_t b = length; |
| 88 | if(cb(&b, 1, app_key) < 0) { |
| 89 | return -1; |
| 90 | } |
| 91 | return 1; |
| 92 | } |
| 93 | |
| 94 | if(*(char *)&littleEndian) { |
| 95 | pstart = (const uint8_t *)&length + sizeof(length); |
| 96 | pend = (const uint8_t *)&length; |
| 97 | add = -1; |
| 98 | } else { |
| 99 | pstart = (const uint8_t *)&length; |
| 100 | pend = pstart + sizeof(length); |
| 101 | add = 1; |
| 102 | } |
| 103 | |
| 104 | for(p = pstart; p != pend; p += add) { |
| 105 | /* Skip leading zeros. */ |
| 106 | if(*p) break; |
| 107 | } |
| 108 | |
| 109 | for(sp = scratch + 1; p != pend; p += add, sp++) { |
| 110 | *sp = *p; |
| 111 | } |
| 112 | assert((sp - scratch) - 1 <= 0x7f); |
| 113 | scratch[0] = 0x80 + ((sp - scratch) - 1); |
| 114 | |
| 115 | if(cb(scratch, sp - scratch, app_key) < 0) { |
| 116 | return -1; |
| 117 | } |
| 118 | |
| 119 | return sp - scratch; |
| 120 | } |
| 121 | |