add proxmox-tfa crate

Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
Wolfgang Bumiller 2021-10-01 10:58:45 +02:00
parent 2859858f59
commit 77dc52c047
12 changed files with 209 additions and 18 deletions

View File

@ -4,6 +4,7 @@ members = [
"proxmox-api-macro",
"proxmox-http",
"proxmox-sortable-macro",
"proxmox-tfa",
]
exclude = [
"build",

View File

@ -1,6 +1,11 @@
# Shortcut for common operations:
CRATES=proxmox proxmox-api-macro proxmox-http proxmox-sortable-macro
CRATES = \
proxmox \
proxmox-api-macro \
proxmox-http \
proxmox-sortable-macro \
proxmox-tfa
# By default we just run checks:
.PHONY: all

25
proxmox-tfa/Cargo.toml Normal file
View File

@ -0,0 +1,25 @@
[package]
name = "proxmox-tfa"
version = "1.0.0"
authors = ["Proxmox Support Team <support@proxmox.com>"]
edition = "2018"
license = "AGPL-3"
description = "tfa implementation for totp and u2f"
exclude = [ "debian" ]
[dependencies]
anyhow = "1.0"
base32 = "0.4"
base64 = "0.12"
hex = "0.4"
openssl = "0.10"
percent-encoding = "2.1"
serde = "1.0"
serde_plain = "1.0"
serde_json = { version = "1.0", optional = true }
libc = { version = "0.2", optional = true }
[features]
default = []
u2f = [ "libc", "serde_json", "serde/derive" ]

View File

@ -0,0 +1,5 @@
rust-proxmox-tfa (1.0.0-1) stable; urgency=medium
* initial split out of `librust-proxmox-dev`
-- Proxmox Support Team <support@proxmox.com> Mon, 04 Oct 2021 11:38:53 +0200

View File

@ -0,0 +1,97 @@
Source: rust-proxmox-tfa
Section: rust
Priority: optional
Build-Depends: debhelper (>= 12),
dh-cargo (>= 24),
cargo:native <!nocheck>,
rustc:native <!nocheck>,
libstd-rust-dev <!nocheck>,
librust-anyhow-1+default-dev <!nocheck>,
librust-base32-0.4+default-dev <!nocheck>,
librust-base64-0.12+default-dev <!nocheck>,
librust-hex-0.4+default-dev <!nocheck>,
librust-openssl-0.10+default-dev <!nocheck>,
librust-percent-encoding-2+default-dev (>= 2.1-~~) <!nocheck>,
librust-serde-1+default-dev <!nocheck>,
librust-serde-plain-1+default-dev <!nocheck>
Maintainer: Proxmox Support Team <support@proxmox.com>
Standards-Version: 4.5.1
Vcs-Git: git://git.proxmox.com/git/proxmox.git
Vcs-Browser: https://git.proxmox.com/?p=proxmox.git
Rules-Requires-Root: no
Package: librust-proxmox-tfa-dev
Architecture: any
Multi-Arch: same
Depends:
${misc:Depends},
librust-anyhow-1+default-dev,
librust-base32-0.4+default-dev,
librust-base64-0.12+default-dev,
librust-hex-0.4+default-dev,
librust-openssl-0.10+default-dev,
librust-percent-encoding-2+default-dev (>= 2.1-~~),
librust-serde-1+default-dev,
librust-serde-plain-1+default-dev
Suggests:
librust-proxmox-tfa+libc-dev (= ${binary:Version}),
librust-proxmox-tfa+serde-json-dev (= ${binary:Version}),
librust-proxmox-tfa+u2f-dev (= ${binary:Version})
Provides:
librust-proxmox-tfa+default-dev (= ${binary:Version}),
librust-proxmox-tfa-1-dev (= ${binary:Version}),
librust-proxmox-tfa-1+default-dev (= ${binary:Version}),
librust-proxmox-tfa-1.0-dev (= ${binary:Version}),
librust-proxmox-tfa-1.0+default-dev (= ${binary:Version}),
librust-proxmox-tfa-1.0.0-dev (= ${binary:Version}),
librust-proxmox-tfa-1.0.0+default-dev (= ${binary:Version})
Description: Tfa implementation for totp and u2f - Rust source code
This package contains the source for the Rust proxmox-tfa crate, packaged by
debcargo for use with cargo and dh-cargo.
Package: librust-proxmox-tfa+libc-dev
Architecture: any
Multi-Arch: same
Depends:
${misc:Depends},
librust-proxmox-tfa-dev (= ${binary:Version}),
librust-libc-0.2+default-dev
Provides:
librust-proxmox-tfa-1+libc-dev (= ${binary:Version}),
librust-proxmox-tfa-1.0+libc-dev (= ${binary:Version}),
librust-proxmox-tfa-1.0.0+libc-dev (= ${binary:Version})
Description: Tfa implementation for totp and u2f - feature "libc"
This metapackage enables feature "libc" for the Rust proxmox-tfa crate, by
pulling in any additional dependencies needed by that feature.
Package: librust-proxmox-tfa+serde-json-dev
Architecture: any
Multi-Arch: same
Depends:
${misc:Depends},
librust-proxmox-tfa-dev (= ${binary:Version}),
librust-serde-json-1+default-dev
Provides:
librust-proxmox-tfa-1+serde-json-dev (= ${binary:Version}),
librust-proxmox-tfa-1.0+serde-json-dev (= ${binary:Version}),
librust-proxmox-tfa-1.0.0+serde-json-dev (= ${binary:Version})
Description: Tfa implementation for totp and u2f - feature "serde_json"
This metapackage enables feature "serde_json" for the Rust proxmox-tfa crate,
by pulling in any additional dependencies needed by that feature.
Package: librust-proxmox-tfa+u2f-dev
Architecture: any
Multi-Arch: same
Depends:
${misc:Depends},
librust-proxmox-tfa-dev (= ${binary:Version}),
librust-libc-0.2+default-dev,
librust-serde-1+derive-dev,
librust-serde-json-1+default-dev
Provides:
librust-proxmox-tfa-1+u2f-dev (= ${binary:Version}),
librust-proxmox-tfa-1.0+u2f-dev (= ${binary:Version}),
librust-proxmox-tfa-1.0.0+u2f-dev (= ${binary:Version})
Description: Tfa implementation for totp and u2f - feature "u2f"
This metapackage enables feature "u2f" for the Rust proxmox-tfa crate, by
pulling in any additional dependencies needed by that feature.

View File

@ -0,0 +1,16 @@
Copyright (C) 2021 Proxmox Server Solutions GmbH
This software is written by Proxmox Server Solutions GmbH <support@proxmox.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

View File

@ -0,0 +1,7 @@
overlay = "."
crate_src_path = ".."
maintainer = "Proxmox Support Team <support@proxmox.com>"
[source]
vcs_git = "git://git.proxmox.com/git/proxmox.git"
vcs_browser = "https://git.proxmox.com/?p=proxmox.git"

View File

@ -1,4 +1,4 @@
//! Implementation of TOTP, U2F and other mechanisms.
//! TOTP implementation.
use std::convert::TryFrom;
use std::fmt;
@ -172,7 +172,7 @@ impl Totp {
/// Create a new OTP secret key builder using a secret specified in hexadecimal bytes.
pub fn builder_from_hex(secret: &str) -> Result<TotpBuilder, Error> {
crate::tools::hex_to_bin(secret).map(|secret| Self::builder().secret(secret))
Ok(Self::builder().secret(hex::decode(secret)?))
}
/// Get the secret key in binary form.
@ -394,7 +394,7 @@ impl std::str::FromStr for Totp {
}
}
crate::forward_deserialize_to_from_str!(Totp);
serde_plain::derive_deserialize_from_fromstr!(Totp, "valid TOTP url");
impl Serialize for Totp {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>

View File

@ -1,6 +1,7 @@
//! U2F implementation.
use std::mem::MaybeUninit;
use std::io;
use anyhow::{bail, format_err, Error};
use openssl::ec::{EcGroup, EcKey, EcPoint};
@ -10,8 +11,6 @@ use openssl::sha;
use openssl::x509::X509;
use serde::{Deserialize, Serialize};
use crate::tools::serde::{bytes_as_base64, bytes_as_base64url_nopad};
const CHALLENGE_LEN: usize = 32;
const U2F_VERSION: &str = "U2F_V2";
@ -318,10 +317,19 @@ fn decode(data: &str) -> Result<Vec<u8>, Error> {
/// produce a challenge, which is just a bunch of random data
fn challenge() -> Result<String, Error> {
let mut data = MaybeUninit::<[u8; CHALLENGE_LEN]>::uninit();
Ok(encode(&unsafe {
crate::sys::linux::fill_with_random_data(&mut *data.as_mut_ptr())?;
let data = unsafe {
let buf: &mut [u8; CHALLENGE_LEN] = &mut *data.as_mut_ptr();
let rc = libc::getrandom(buf.as_mut_ptr() as *mut libc::c_void, buf.len(), 0);
if rc == -1 {
return Err(io::Error::last_os_error().into());
}
if rc as usize != buf.len() {
// `CHALLENGE_LEN` is small, so short reads cannot happen (see `getrandom(2)`)
bail!("short getrandom call");
}
data.assume_init()
}))
};
Ok(encode(&data))
}
/// Used while parsing the binary registration response. The slices point directly into the
@ -548,3 +556,37 @@ mod test {
);
}
}
pub mod bytes_as_base64 {
use serde::{Deserialize, Deserializer, Serializer};
pub fn serialize<S: Serializer>(data: &[u8], serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&base64::encode(&data))
}
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D::Error> {
use serde::de::Error;
String::deserialize(deserializer).and_then(|string| {
base64::decode(&string).map_err(|err| Error::custom(err.to_string()))
})
}
}
pub mod bytes_as_base64url_nopad {
use serde::{Deserialize, Deserializer, Serializer};
pub fn serialize<S: Serializer>(data: &[u8], serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&base64::encode_config(
data.as_ref(),
base64::URL_SAFE_NO_PAD,
))
}
pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<u8>, D::Error> {
use serde::de::Error;
String::deserialize(deserializer).and_then(|string| {
base64::decode_config(&string, base64::URL_SAFE_NO_PAD)
.map_err(|err| Error::custom(err.to_string()))
})
}
}

View File

@ -20,7 +20,6 @@ nix = "0.19.1"
unicode-width ="0.1.8"
# tools module:
base32 = { version = "0.4", optional = true }
base64 = "0.12"
endian_trait = { version = "0.6", features = ["arrays"] }
regex = "1.2"
@ -38,7 +37,6 @@ futures = { version = "0.3", optional = true }
http = "0.2"
hyper = { version = "0.14", features = [ "full" ], optional = true }
percent-encoding = "2.1"
openssl = { version = "0.10", optional = true }
rustyline = "7"
textwrap = "0.11"
tokio = { version = "1.0", features = [], optional = true }
@ -51,7 +49,7 @@ proxmox-api-macro = { path = "../proxmox-api-macro", optional = true, version =
proxmox-sortable-macro = { path = "../proxmox-sortable-macro", optional = true, version = "0.1.1" }
[features]
default = [ "cli", "router", "tfa", "u2f" ]
default = [ "cli", "router" ]
sortable-macro = ["proxmox-sortable-macro"]
# api:
@ -59,10 +57,8 @@ api-macro = ["proxmox-api-macro"]
test-harness = []
cli = [ "router", "hyper", "tokio" ]
router = [ "futures", "hyper", "tokio" ]
tfa = [ "openssl" ]
u2f = [ "base32" ]
examples = ["tokio/macros", "u2f"]
examples = ["tokio/macros"]
# tools:
#valgrind = ["proxmox-tools/valgrind"]

View File

@ -22,9 +22,6 @@ pub mod uuid;
pub mod vec;
pub mod systemd;
#[cfg(feature = "tfa")]
pub mod tfa;
#[doc(inline)]
pub use uuid::Uuid;