olm_rs/lib.rs
1// Copyright 2020 Johannes Hayeß
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//! This is a wrapper for [`libolm`](https://git.matrix.org/git/olm/about/).
16//! It exposes all original functionality, split into task oriented modules.
17//!
18//! This wrapper takes care of memory allocation for you, so all functions
19//! in the original library exposing the buffer length of certain read/write
20//! buffers (and similar functionality) are not exposed by this wrapper.
21//!
22//! Random number generation is also handled internally and hence there are no
23//! function arguments for supplying random data.
24//!
25//! String arguments will vary in ownership requirements when being provided as a
26//! function argument. This is because `libolm` will sometimes mutate this data and
27//! sometimes won't. To avoid breaking the ownership model, full ownership is required
28//! for the former case.
29//!
30//! All errors of the type `NOT_ENOUGH_RANDOM` and `OUTPUT_BUFFER_TOO_SMALL` from
31//! `libolm` that are encountered result in a panic, as they are unrecoverably fatal.
32//! Similarly the output from `libolm` is assumed to be trusted, except for encryption
33//! functions. If the string output from any other function is not properly encoded
34//! as UTF-8, a panic will occur as well.
35//! In case a function can panic, it is annotated as such in the documentation.
36//!
37//! All panics can be considered unreachable, they are documented however for the
38//! purpose of transparency.
39
40pub mod account;
41pub mod errors;
42pub mod inbound_group_session;
43pub mod outbound_group_session;
44pub mod pk;
45pub mod sas;
46pub mod session;
47pub mod utility;
48
49use std::alloc::{GlobalAlloc as _, Layout, System};
50use std::fmt;
51use std::os::raw::c_void;
52use std::ptr;
53
54use getrandom as random;
55use zeroize::Zeroizing;
56
57/// A [`mod@getrandom`] wrapper that panics if the call is unsuccessful.
58///
59/// # Arguments
60///
61/// * `buffer` - The buffer that should be filled with random data.
62///
63/// # Panics
64///
65/// Panics if the operating system can't provide enough random data.
66pub(crate) fn getrandom(buffer: &mut Zeroizing<Vec<u8>>) {
67 random::getrandom(buffer).expect(
68 "Operating system didn't provide enough random data to securely generate the private keys.",
69 );
70}
71
72/// Marking these as Send is safe because nothing will modify the pointer under
73/// us from the C side. Sync on the other hand is unsafe since libolm doesn't do
74/// any synchronization.
75unsafe impl Send for account::OlmAccount {}
76unsafe impl Send for session::OlmSession {}
77unsafe impl Send for sas::OlmSas {}
78unsafe impl Send for pk::OlmPkDecryption {}
79unsafe impl Send for pk::OlmPkEncryption {}
80unsafe impl Send for pk::OlmPkSigning {}
81unsafe impl Send for inbound_group_session::OlmInboundGroupSession {}
82unsafe impl Send for outbound_group_session::OlmOutboundGroupSession {}
83
84/// Used for storing the version number of libolm.
85/// Solely returned by [`get_library_version()`](fn.get_library_version.html).
86#[derive(Debug, PartialEq)]
87pub struct OlmVersion {
88 pub major: u8,
89 pub minor: u8,
90 pub patch: u8,
91}
92
93/// Used for setting the encryption parameter for pickling (serialisation) functions.
94/// `Unencrypted` is functionally equivalent to `Encrypted{key: [].to_vec() }`, but is much more clear.
95/// Pickling modes have to be equivalent for pickling and unpickling operations to succeed.
96/// `Encrypted` takes ownership of `key`, in order to properly destroy it after use.
97pub enum PicklingMode {
98 Unencrypted,
99 Encrypted { key: Vec<u8> },
100}
101
102/// Convenience function that maps `Unencrypted` to an empty key, or
103/// unwraps `Encrypted`. Mostly for reducing code duplication.
104pub(crate) fn convert_pickling_mode_to_key(mode: PicklingMode) -> Vec<u8> {
105 match mode {
106 PicklingMode::Unencrypted => Vec::new(),
107 PicklingMode::Encrypted { key: x } => x,
108 }
109}
110
111/// Returns the version number of the currently utilised `libolm`.
112///
113/// # C-API equivalent
114/// `olm_get_library_version`
115pub fn get_library_version() -> OlmVersion {
116 let mut major = 0;
117 let mut minor = 0;
118 let mut patch = 0;
119 let major_ptr: *mut u8 = &mut major;
120 let minor_ptr: *mut u8 = &mut minor;
121 let patch_ptr: *mut u8 = &mut patch;
122
123 unsafe {
124 olm_sys::olm_get_library_version(major_ptr, minor_ptr, patch_ptr);
125 }
126
127 OlmVersion {
128 major,
129 minor,
130 patch,
131 }
132}
133
134/// Helper type that just holds a one byte aligned allocation but doesn't allow
135/// safe code to access its contents.
136///
137/// For use with the olm functions that take a buffer and return a typed pointer
138/// into the same allocation after initializing it.
139struct ByteBuf(*mut [u8]);
140
141impl ByteBuf {
142 fn new(size: usize) -> Self {
143 assert!(size != 0);
144
145 let layout = Layout::from_size_align(size, 1).unwrap();
146 let data = unsafe { System.alloc(layout) };
147 Self(ptr::slice_from_raw_parts_mut(data, size))
148 }
149
150 fn as_mut_void_ptr(&mut self) -> *mut c_void {
151 self.0 as _
152 }
153}
154
155impl fmt::Debug for ByteBuf {
156 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
157 write!(f, "<ByteBuf>")
158 }
159}
160
161impl Drop for ByteBuf {
162 fn drop(&mut self) {
163 // Should ideally use the safe <*mut [T]>::len(), but that is unstable.
164 // https://github.com/rust-lang/rust/issues/71146
165 let size = unsafe { (*self.0).len() };
166 let layout = Layout::from_size_align(size, 1).unwrap();
167
168 // Should ideally use <*mut [T]>::as_mut_ptr(), but that is unstable.
169 // https://github.com/rust-lang/rust/issues/74265
170 let data = self.0 as *mut u8;
171
172 unsafe {
173 System.dealloc(data, layout);
174 }
175 }
176}