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}