• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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