1 // Copyright 2022 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://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,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 //! V1 advertisement support.
16 use crate::DeLengthOutOfRange;
17 use array_view::ArrayView;
18 use crypto_provider::CryptoRng;
19
20 pub mod data_elements;
21 pub mod de_type;
22 pub mod deserialize;
23 pub mod salt;
24 pub mod section_signature_payload;
25 pub mod serialize;
26
27 // TODO make this easy to use w/ configurable arena size
28 /// Maximum size of an NP advertisement, including the adv header
29 pub const BLE_5_ADV_SVC_MAX_CONTENT_LEN: usize = 254
30 // length and type bytes for svc data TLV
31 - 1 - 1
32 // NP UUID
33 - 2;
34
35 /// Maximum number of sections in an advertisement
36 pub const NP_V1_ADV_MAX_ENCRYPTED_SECTION_COUNT: usize = 8;
37
38 /// Maximum number of public sections in an advertisement
39 pub const NP_V1_ADV_MAX_PUBLIC_SECTION_COUNT: usize = 1;
40
41 /// Maximum size of a NP section, including its length header byte
42 pub const NP_ADV_MAX_SECTION_LEN: usize = NP_ADV_MAX_SECTION_CONTENTS_LEN + 1;
43
44 // TODO should this be 255 (or 256, if we +1 the length)?
45 /// Maximum hypothetical size of a NP section's contents, excluding its header
46 /// byte. This is longer than can fit in a BLE 5 extended adv, but other media
47 /// could fit it, like mDNS.
48 const NP_ADV_MAX_SECTION_CONTENTS_LEN: usize = 255;
49
50 /// Size of a V1 identity token
51 pub const V1_IDENTITY_TOKEN_LEN: usize = 16;
52
53 // 4-bit encoding ids
54 /// Encoding ID for unencrypted sections with no salt
55 pub const V1_ENCODING_UNENCRYPTED: u8 = 0x00;
56 /// Encoding ID for encrypted sections with a MIC and a short salt
57 pub const V1_ENCODING_ENCRYPTED_MIC_WITH_SHORT_SALT_AND_TOKEN: u8 = 0x01;
58 /// Encoding ID for encrypted sections with a MIC and an extended salt
59 pub const V1_ENCODING_ENCRYPTED_MIC_WITH_EXTENDED_SALT_AND_TOKEN: u8 = 0x02;
60 /// Encoding ID for encrypted sections with a signature and an extended salt
61 pub const V1_ENCODING_ENCRYPTED_SIGNATURE_WITH_EXTENDED_SALT_AND_TOKEN: u8 = 0x03;
62
63 // The maximum de length that fits into a non-extended de header
64 const MAX_NON_EXTENDED_LEN: u8 = 7;
65 // The maximum type code that fits into a non-extended de header
66 const MAX_NON_EXTENDED_TYPE_CODE: u32 = 15;
67
de_requires_extended_bit(type_code: u32, de_len: u8) -> bool68 fn de_requires_extended_bit(type_code: u32, de_len: u8) -> bool {
69 de_len > MAX_NON_EXTENDED_LEN || type_code > MAX_NON_EXTENDED_TYPE_CODE
70 }
71
72 /// 16-byte plaintext identity token.
73 ///
74 /// Identity tokens are present in encrypted form in a section's header.
75 #[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
76 pub struct V1IdentityToken([u8; V1_IDENTITY_TOKEN_LEN]);
77
78 impl From<[u8; V1_IDENTITY_TOKEN_LEN]> for V1IdentityToken {
from(value: [u8; V1_IDENTITY_TOKEN_LEN]) -> Self79 fn from(value: [u8; V1_IDENTITY_TOKEN_LEN]) -> Self {
80 Self(value)
81 }
82 }
83
84 impl V1IdentityToken {
85 /// Returns a reference to the inner byte array
bytes(&self) -> &[u8; V1_IDENTITY_TOKEN_LEN]86 pub fn bytes(&self) -> &[u8; V1_IDENTITY_TOKEN_LEN] {
87 &self.0
88 }
89
90 /// Returns the inner byte array
into_bytes(self) -> [u8; V1_IDENTITY_TOKEN_LEN]91 pub const fn into_bytes(self) -> [u8; V1_IDENTITY_TOKEN_LEN] {
92 self.0
93 }
94
95 /// Returns the token bytes as a slice
as_slice(&self) -> &[u8]96 pub fn as_slice(&self) -> &[u8] {
97 &self.0
98 }
99 }
100
101 impl AsRef<[u8]> for V1IdentityToken {
as_ref(&self) -> &[u8]102 fn as_ref(&self) -> &[u8] {
103 &self.0
104 }
105 }
106
107 impl crypto_provider::FromCryptoRng for V1IdentityToken {
new_random<R: CryptoRng>(rng: &mut R) -> Self108 fn new_random<R: CryptoRng>(rng: &mut R) -> Self {
109 Self(rng.gen())
110 }
111 }
112
113 /// Max V1 DE length (7 bit length field).
114 pub(crate) const MAX_DE_LEN: usize = 127;
115
116 /// Length of a DE's content -- must be in `[0, 127]`
117 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
118 pub struct DeLength {
119 len: u8,
120 }
121
122 impl DeLength {
123 /// A convenient constant for zero length.
124 pub const ZERO: DeLength = DeLength { len: 0 };
125
as_u8(&self) -> u8126 fn as_u8(&self) -> u8 {
127 self.len
128 }
129 }
130
131 impl TryFrom<u8> for DeLength {
132 type Error = DeLengthOutOfRange;
133
try_from(value: u8) -> Result<Self, Self::Error>134 fn try_from(value: u8) -> Result<Self, Self::Error> {
135 if usize::from(value) <= MAX_DE_LEN {
136 Ok(Self { len: value })
137 } else {
138 Err(DeLengthOutOfRange {})
139 }
140 }
141 }
142
143 impl TryFrom<usize> for DeLength {
144 type Error = DeLengthOutOfRange;
145
try_from(value: usize) -> Result<Self, Self::Error>146 fn try_from(value: usize) -> Result<Self, Self::Error> {
147 value.try_into().map_err(|_e| DeLengthOutOfRange).and_then(|num: u8| num.try_into())
148 }
149 }
150
151 /// Convert a tinyvec into an equivalent ArrayView
to_array_view<T, const N: usize>(vec: tinyvec::ArrayVec<[T; N]>) -> ArrayView<T, N> where [T; N]: tinyvec::Array,152 pub(crate) fn to_array_view<T, const N: usize>(vec: tinyvec::ArrayVec<[T; N]>) -> ArrayView<T, N>
153 where
154 [T; N]: tinyvec::Array,
155 {
156 let len = vec.len();
157 ArrayView::try_from_array(vec.into_inner(), len).expect("len is from original vec")
158 }
159
160 #[cfg(test)]
161 mod tests {
162 use super::*;
163 use rand::{distributions, Rng};
164
165 // support randomly generating tokens just for tests
166 impl distributions::Distribution<V1IdentityToken> for distributions::Standard {
sample<R: Rng + ?Sized>(&self, rng: &mut R) -> V1IdentityToken167 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> V1IdentityToken {
168 V1IdentityToken::from(rng.gen::<[u8; V1_IDENTITY_TOKEN_LEN]>())
169 }
170 }
171 }
172