add proxmox-tfa crate
Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
2859858f59
commit
77dc52c047
@ -4,6 +4,7 @@ members = [
|
|||||||
"proxmox-api-macro",
|
"proxmox-api-macro",
|
||||||
"proxmox-http",
|
"proxmox-http",
|
||||||
"proxmox-sortable-macro",
|
"proxmox-sortable-macro",
|
||||||
|
"proxmox-tfa",
|
||||||
]
|
]
|
||||||
exclude = [
|
exclude = [
|
||||||
"build",
|
"build",
|
||||||
|
7
Makefile
7
Makefile
@ -1,6 +1,11 @@
|
|||||||
# Shortcut for common operations:
|
# 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:
|
# By default we just run checks:
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
|
25
proxmox-tfa/Cargo.toml
Normal file
25
proxmox-tfa/Cargo.toml
Normal 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" ]
|
5
proxmox-tfa/debian/changelog
Normal file
5
proxmox-tfa/debian/changelog
Normal 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
|
97
proxmox-tfa/debian/control
Normal file
97
proxmox-tfa/debian/control
Normal 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.
|
16
proxmox-tfa/debian/copyright
Normal file
16
proxmox-tfa/debian/copyright
Normal 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/>.
|
7
proxmox-tfa/debian/debcargo.toml
Normal file
7
proxmox-tfa/debian/debcargo.toml
Normal 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"
|
@ -1,4 +1,4 @@
|
|||||||
//! Implementation of TOTP, U2F and other mechanisms.
|
//! TOTP implementation.
|
||||||
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@ -172,7 +172,7 @@ impl Totp {
|
|||||||
|
|
||||||
/// Create a new OTP secret key builder using a secret specified in hexadecimal bytes.
|
/// Create a new OTP secret key builder using a secret specified in hexadecimal bytes.
|
||||||
pub fn builder_from_hex(secret: &str) -> Result<TotpBuilder, Error> {
|
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.
|
/// 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 {
|
impl Serialize for Totp {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
@ -1,6 +1,7 @@
|
|||||||
//! U2F implementation.
|
//! U2F implementation.
|
||||||
|
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
use anyhow::{bail, format_err, Error};
|
use anyhow::{bail, format_err, Error};
|
||||||
use openssl::ec::{EcGroup, EcKey, EcPoint};
|
use openssl::ec::{EcGroup, EcKey, EcPoint};
|
||||||
@ -10,8 +11,6 @@ use openssl::sha;
|
|||||||
use openssl::x509::X509;
|
use openssl::x509::X509;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::tools::serde::{bytes_as_base64, bytes_as_base64url_nopad};
|
|
||||||
|
|
||||||
const CHALLENGE_LEN: usize = 32;
|
const CHALLENGE_LEN: usize = 32;
|
||||||
const U2F_VERSION: &str = "U2F_V2";
|
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
|
/// produce a challenge, which is just a bunch of random data
|
||||||
fn challenge() -> Result<String, Error> {
|
fn challenge() -> Result<String, Error> {
|
||||||
let mut data = MaybeUninit::<[u8; CHALLENGE_LEN]>::uninit();
|
let mut data = MaybeUninit::<[u8; CHALLENGE_LEN]>::uninit();
|
||||||
Ok(encode(&unsafe {
|
let data = unsafe {
|
||||||
crate::sys::linux::fill_with_random_data(&mut *data.as_mut_ptr())?;
|
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()
|
data.assume_init()
|
||||||
}))
|
};
|
||||||
|
Ok(encode(&data))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used while parsing the binary registration response. The slices point directly into the
|
/// 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()))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -20,7 +20,6 @@ nix = "0.19.1"
|
|||||||
unicode-width ="0.1.8"
|
unicode-width ="0.1.8"
|
||||||
|
|
||||||
# tools module:
|
# tools module:
|
||||||
base32 = { version = "0.4", optional = true }
|
|
||||||
base64 = "0.12"
|
base64 = "0.12"
|
||||||
endian_trait = { version = "0.6", features = ["arrays"] }
|
endian_trait = { version = "0.6", features = ["arrays"] }
|
||||||
regex = "1.2"
|
regex = "1.2"
|
||||||
@ -38,7 +37,6 @@ futures = { version = "0.3", optional = true }
|
|||||||
http = "0.2"
|
http = "0.2"
|
||||||
hyper = { version = "0.14", features = [ "full" ], optional = true }
|
hyper = { version = "0.14", features = [ "full" ], optional = true }
|
||||||
percent-encoding = "2.1"
|
percent-encoding = "2.1"
|
||||||
openssl = { version = "0.10", optional = true }
|
|
||||||
rustyline = "7"
|
rustyline = "7"
|
||||||
textwrap = "0.11"
|
textwrap = "0.11"
|
||||||
tokio = { version = "1.0", features = [], optional = true }
|
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" }
|
proxmox-sortable-macro = { path = "../proxmox-sortable-macro", optional = true, version = "0.1.1" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = [ "cli", "router", "tfa", "u2f" ]
|
default = [ "cli", "router" ]
|
||||||
sortable-macro = ["proxmox-sortable-macro"]
|
sortable-macro = ["proxmox-sortable-macro"]
|
||||||
|
|
||||||
# api:
|
# api:
|
||||||
@ -59,10 +57,8 @@ api-macro = ["proxmox-api-macro"]
|
|||||||
test-harness = []
|
test-harness = []
|
||||||
cli = [ "router", "hyper", "tokio" ]
|
cli = [ "router", "hyper", "tokio" ]
|
||||||
router = [ "futures", "hyper", "tokio" ]
|
router = [ "futures", "hyper", "tokio" ]
|
||||||
tfa = [ "openssl" ]
|
|
||||||
u2f = [ "base32" ]
|
|
||||||
|
|
||||||
examples = ["tokio/macros", "u2f"]
|
examples = ["tokio/macros"]
|
||||||
|
|
||||||
# tools:
|
# tools:
|
||||||
#valgrind = ["proxmox-tools/valgrind"]
|
#valgrind = ["proxmox-tools/valgrind"]
|
||||||
|
@ -22,9 +22,6 @@ pub mod uuid;
|
|||||||
pub mod vec;
|
pub mod vec;
|
||||||
pub mod systemd;
|
pub mod systemd;
|
||||||
|
|
||||||
#[cfg(feature = "tfa")]
|
|
||||||
pub mod tfa;
|
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use uuid::Uuid;
|
pub use uuid::Uuid;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user