1 // Copyright 2021 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "dice/cbor_writer.h"
16
17 #include <stdbool.h>
18 #include <stddef.h>
19 #include <stdint.h>
20 #include <string.h>
21
22 enum CborType {
23 CBOR_TYPE_UINT = 0,
24 CBOR_TYPE_NINT = 1,
25 CBOR_TYPE_BSTR = 2,
26 CBOR_TYPE_TSTR = 3,
27 CBOR_TYPE_ARRAY = 4,
28 CBOR_TYPE_MAP = 5,
29 CBOR_TYPE_TAG = 6,
30 CBOR_TYPE_SIMPLE = 7,
31 };
32
CborWriteWouldOverflowCursor(size_t size,struct CborOut * out)33 static bool CborWriteWouldOverflowCursor(size_t size, struct CborOut* out) {
34 return size > SIZE_MAX - out->cursor;
35 }
36
CborWriteFitsInBuffer(size_t size,struct CborOut * out)37 static bool CborWriteFitsInBuffer(size_t size, struct CborOut* out) {
38 return out->cursor <= out->buffer_size &&
39 size <= out->buffer_size - out->cursor;
40 }
41
CborWriteType(enum CborType type,uint64_t val,struct CborOut * out)42 static void CborWriteType(enum CborType type, uint64_t val,
43 struct CborOut* out) {
44 size_t size;
45 if (val <= 23) {
46 size = 1;
47 } else if (val <= 0xff) {
48 size = 2;
49 } else if (val <= 0xffff) {
50 size = 3;
51 } else if (val <= 0xffffffff) {
52 size = 5;
53 } else {
54 size = 9;
55 }
56 if (CborWriteWouldOverflowCursor(size, out)) {
57 out->cursor = SIZE_MAX;
58 return;
59 }
60 if (CborWriteFitsInBuffer(size, out)) {
61 if (size == 1) {
62 out->buffer[out->cursor] = (type << 5) | val;
63 } else if (size == 2) {
64 out->buffer[out->cursor] = (type << 5) | 24;
65 out->buffer[out->cursor + 1] = val & 0xff;
66 } else if (size == 3) {
67 out->buffer[out->cursor] = (type << 5) | 25;
68 out->buffer[out->cursor + 1] = (val >> 8) & 0xff;
69 out->buffer[out->cursor + 2] = val & 0xff;
70 } else if (size == 5) {
71 out->buffer[out->cursor] = (type << 5) | 26;
72 out->buffer[out->cursor + 1] = (val >> 24) & 0xff;
73 out->buffer[out->cursor + 2] = (val >> 16) & 0xff;
74 out->buffer[out->cursor + 3] = (val >> 8) & 0xff;
75 out->buffer[out->cursor + 4] = val & 0xff;
76 } else if (size == 9) {
77 out->buffer[out->cursor] = (type << 5) | 27;
78 out->buffer[out->cursor + 1] = (val >> 56) & 0xff;
79 out->buffer[out->cursor + 2] = (val >> 48) & 0xff;
80 out->buffer[out->cursor + 3] = (val >> 40) & 0xff;
81 out->buffer[out->cursor + 4] = (val >> 32) & 0xff;
82 out->buffer[out->cursor + 5] = (val >> 24) & 0xff;
83 out->buffer[out->cursor + 6] = (val >> 16) & 0xff;
84 out->buffer[out->cursor + 7] = (val >> 8) & 0xff;
85 out->buffer[out->cursor + 8] = val & 0xff;
86 }
87 }
88 out->cursor += size;
89 }
90
CborAllocStr(enum CborType type,size_t data_size,struct CborOut * out)91 static void* CborAllocStr(enum CborType type, size_t data_size,
92 struct CborOut* out) {
93 CborWriteType(type, data_size, out);
94 bool overflow = CborWriteWouldOverflowCursor(data_size, out);
95 bool fit = CborWriteFitsInBuffer(data_size, out);
96 void* ptr = (overflow || !fit) ? NULL : &out->buffer[out->cursor];
97 out->cursor = overflow ? SIZE_MAX : out->cursor + data_size;
98 return ptr;
99 }
100
CborWriteStr(enum CborType type,size_t data_size,const void * data,struct CborOut * out)101 static void CborWriteStr(enum CborType type, size_t data_size, const void* data,
102 struct CborOut* out) {
103 uint8_t* ptr = CborAllocStr(type, data_size, out);
104 if (ptr && data_size) {
105 memcpy(ptr, data, data_size);
106 }
107 }
108
CborWriteInt(int64_t val,struct CborOut * out)109 void CborWriteInt(int64_t val, struct CborOut* out) {
110 if (val < 0) {
111 CborWriteType(CBOR_TYPE_NINT, (-1 - val), out);
112 } else {
113 CborWriteType(CBOR_TYPE_UINT, val, out);
114 }
115 }
116
CborWriteUint(uint64_t val,struct CborOut * out)117 void CborWriteUint(uint64_t val, struct CborOut* out) {
118 CborWriteType(CBOR_TYPE_UINT, val, out);
119 }
120
CborWriteBstr(size_t data_size,const uint8_t * data,struct CborOut * out)121 void CborWriteBstr(size_t data_size, const uint8_t* data, struct CborOut* out) {
122 CborWriteStr(CBOR_TYPE_BSTR, data_size, data, out);
123 }
124
CborAllocBstr(size_t data_size,struct CborOut * out)125 uint8_t* CborAllocBstr(size_t data_size, struct CborOut* out) {
126 return CborAllocStr(CBOR_TYPE_BSTR, data_size, out);
127 }
128
CborWriteTstr(const char * str,struct CborOut * out)129 void CborWriteTstr(const char* str, struct CborOut* out) {
130 CborWriteStr(CBOR_TYPE_TSTR, strlen(str), str, out);
131 }
132
CborAllocTstr(size_t size,struct CborOut * out)133 char* CborAllocTstr(size_t size, struct CborOut* out) {
134 return CborAllocStr(CBOR_TYPE_TSTR, size, out);
135 }
136
CborWriteArray(size_t num_elements,struct CborOut * out)137 void CborWriteArray(size_t num_elements, struct CborOut* out) {
138 CborWriteType(CBOR_TYPE_ARRAY, num_elements, out);
139 }
140
CborWriteMap(size_t num_pairs,struct CborOut * out)141 void CborWriteMap(size_t num_pairs, struct CborOut* out) {
142 CborWriteType(CBOR_TYPE_MAP, num_pairs, out);
143 }
144
CborWriteTag(uint64_t tag,struct CborOut * out)145 void CborWriteTag(uint64_t tag, struct CborOut* out) {
146 CborWriteType(CBOR_TYPE_TAG, tag, out);
147 }
148
CborWriteFalse(struct CborOut * out)149 void CborWriteFalse(struct CborOut* out) {
150 CborWriteType(CBOR_TYPE_SIMPLE, /*val=*/20, out);
151 }
152
CborWriteTrue(struct CborOut * out)153 void CborWriteTrue(struct CborOut* out) {
154 CborWriteType(CBOR_TYPE_SIMPLE, /*val=*/21, out);
155 }
156
CborWriteNull(struct CborOut * out)157 void CborWriteNull(struct CborOut* out) {
158 CborWriteType(CBOR_TYPE_SIMPLE, /*val=*/22, out);
159 }
160