blob: b15a3bc93975ab8c68c93403e602069b2e149d72 [file] [log] [blame]
Lev Walkine4d8c922017-07-10 20:29:33 -07001/*
2 * Copyright (c) 2017 Lev Walkin <vlm@lionet.info>.
3 * All rights reserved.
Lev Walkin086ee9a2017-08-08 02:05:55 -07004 * Redistribution and modifications are permitted subject to BSD license.
Lev Walkine4d8c922017-07-10 20:29:33 -07005 */
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 */
18ssize_t
19oer_fetch_length(const void *bufptr, size_t size, size_t *len_r) {
20 uint8_t first_byte;
Vasil Velichkov3875d502017-10-19 03:50:22 +030021 size_t len_len; /* Length of the length determinant */
Lev Walkine4d8c922017-07-10 20:29:33 -070022 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);
Vasil Velichkov3875d502017-10-19 03:50:22 +030038 if((1 + len_len) > size) {
Lev Walkine4d8c922017-07-10 20:29:33 -070039 *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 Walkin494fb702017-08-07 20:07:00 -070050 if((bend - b) > (ssize_t)sizeof(size_t)) {
Lev Walkine4d8c922017-07-10 20:29:33 -070051 /* 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 Walkinc6bd3592017-08-30 17:36:23 -070060 if(len > RSIZE_MAX) { /* A bit of C11 validation */
61 *len_r = 0;
Lev Walkin39837e62017-07-20 14:51:08 +030062 return -1;
Lev Walkinc6bd3592017-08-30 17:36:23 -070063 }
Lev Walkin39837e62017-07-20 14:51:08 +030064
Lev Walkine4d8c922017-07-10 20:29:33 -070065 *len_r = len;
Vasil Velichkovc8bc5732017-10-19 04:27:44 +030066 assert(len_len + 1 == (size_t)(bend - (const uint8_t *)bufptr));
Lev Walkine4d8c922017-07-10 20:29:33 -070067 return len_len + 1;
68}
69
70
Lev Walkinfcfe19b2017-07-10 21:57:14 -070071/*
72 * Serialize OER length. Returns the number of bytes serialized
73 * or -1 if a given callback returned with negative result.
74 */
75ssize_t
76oer_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) {
Lev Walkind17cf882017-10-01 22:46:23 -070095 pstart = (const uint8_t *)&length + sizeof(length) - 1;
Lev Walkinfcfe19b2017-07-10 21:57:14 -070096 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
Lev Walkind17cf882017-10-01 22:46:23 -0700109 for(sp = scratch + 1; ; p += add) {
110 *sp++ = *p;
111 if(p == pend) break;
Lev Walkinfcfe19b2017-07-10 21:57:14 -0700112 }
113 assert((sp - scratch) - 1 <= 0x7f);
114 scratch[0] = 0x80 + ((sp - scratch) - 1);
115
116 if(cb(scratch, sp - scratch, app_key) < 0) {
117 return -1;
118 }
119
120 return sp - scratch;
121}
122