1 /*
2  * Copyright 2021, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "host/libs/confui/cbor.h"
18 
19 #include "common/libs/confui/confui.h"
20 
21 namespace cuttlefish {
22 namespace confui {
23 /**
24  * basically, this creates a map as follows:
25  * {"prompt" : prompt_text_in_UTF8,
26  *  "extra"  : extra_data_in_bytes}
27  */
Init()28 void Cbor::Init() {
29   cn_cbor_errback err;
30   cb_map_ = std::unique_ptr<cn_cbor, CborDeleter>(cn_cbor_map_create(&err));
31 
32   buffer_status_ = CheckUTF8Copy(prompt_text_);
33   if (!IsOk()) {
34     return;
35   }
36 
37   auto cb_prompt_as_value = cn_cbor_string_create(prompt_text_.data(), &err);
38   auto cb_extra_data_as_value =
39       cn_cbor_data_create(extra_data_.data(), extra_data_.size(), &err);
40   cn_cbor_mapput_string(cb_map_.get(), "prompt", cb_prompt_as_value, &err);
41   cn_cbor_mapput_string(cb_map_.get(), "extra", cb_extra_data_as_value, &err);
42 
43   // cn_cbor_encoder_write wants buffer_ to have a trailing 0 at the end
44   auto n_chars =
45       cn_cbor_encoder_write(buffer_.data(), 0, buffer_.size(), cb_map_.get());
46   ConfUiLog(ERROR) << "Cn-cbor encoder wrote " << n_chars << " while "
47                    << "kMax is " << kMax;
48   if (n_chars < 0) {
49     // it's either message being too long, or a potential cn_cbor bug
50     ConfUiLog(ERROR) << "Cn-cbor returns -1 which is likely message too long.";
51     buffer_status_ = Error::OUT_OF_DATA;
52   }
53   if (!IsOk()) {
54     return;
55   }
56   buffer_.resize(n_chars);
57 }
58 
GetMessage()59 std::vector<std::uint8_t>&& Cbor::GetMessage() { return std::move(buffer_); }
60 
CheckUTF8Copy(const std::string & text)61 Cbor::Error Cbor::CheckUTF8Copy(const std::string& text) {
62   auto begin = text.cbegin();
63   auto end = text.cend();
64 
65   if (!IsOk()) {
66     return buffer_status_;
67   }
68 
69   uint32_t multi_byte_length = 0;
70   Cbor::Error err_code = buffer_status_;  // OK
71 
72   while (begin != end) {
73     if (multi_byte_length) {
74       // parsing multi byte character - must start with 10xxxxxx
75       --multi_byte_length;
76       if ((*begin & 0xc0) != 0x80) {
77         return Cbor::Error::MALFORMED_UTF8;
78       }
79     } else if (!((*begin) & 0x80)) {
80       // 7bit character -> nothing to be done
81     } else {
82       // msb is set and we were not parsing a multi byte character
83       // so this must be a header byte
84       char c = *begin << 1;
85       while (c & 0x80) {
86         ++multi_byte_length;
87         c <<= 1;
88       }
89       // headers of the form 10xxxxxx are not allowed
90       if (multi_byte_length < 1) {
91         return Cbor::Error::MALFORMED_UTF8;
92       }
93       // chars longer than 4 bytes are not allowed (multi_byte_length does not
94       // count the header thus > 3
95       if (multi_byte_length > 3) {
96         return Cbor::Error::MALFORMED_UTF8;
97       }
98     }
99     ++begin;
100   }
101   // if the string ends in the middle of a multi byte char it is invalid
102   if (multi_byte_length) {
103     return Cbor::Error::MALFORMED_UTF8;
104   }
105   return err_code;
106 }
107 }  // end of namespace confui
108 }  // end of namespace cuttlefish
109