1 use anyhow
::{bail, format_err, Error}
;
2 use lazy_static
::lazy_static
;
4 use openssl
::rsa
::{Rsa}
;
5 use openssl
::pkey
::{PKey, Public, Private}
;
8 use std
::path
::PathBuf
;
10 use proxmox
::tools
::fs
::{file_get_contents, replace_file, CreateOptions}
;
11 use proxmox
::try_block
;
13 use crate::api2
::types
::Userid
;
15 fn compute_csrf_secret_digest(
21 let mut hasher
= sha
::Sha256
::new();
22 let data
= format
!("{:08X}:{}:", timestamp
, userid
);
23 hasher
.update(data
.as_bytes());
24 hasher
.update(secret
);
26 base64
::encode_config(&hasher
.finish(), base64
::STANDARD_NO_PAD
)
29 pub fn assemble_csrf_prevention_token(
34 let epoch
= proxmox
::tools
::time
::epoch_i64();
36 let digest
= compute_csrf_secret_digest(epoch
, secret
, userid
);
38 format
!("{:08X}:{}", epoch
, digest
)
41 pub fn verify_csrf_prevention_token(
47 ) -> Result
<i64, Error
> {
49 use std
::collections
::VecDeque
;
51 let mut parts
: VecDeque
<&str> = token
.split('
:'
).collect();
56 bail
!("format error - wrong number of parts.");
59 let timestamp
= parts
.pop_front().unwrap();
60 let sig
= parts
.pop_front().unwrap();
62 let ttime
= i64::from_str_radix(timestamp
, 16).
63 map_err(|err
| format_err
!("timestamp format error - {}", err
))?
;
65 let digest
= compute_csrf_secret_digest(ttime
, secret
, userid
);
68 bail
!("invalid signature.");
71 let now
= proxmox
::tools
::time
::epoch_i64();
73 let age
= now
- ttime
;
75 bail
!("timestamp newer than expected.");
79 bail
!("timestamp too old.");
83 }).map_err(|err
| format_err
!("invalid csrf token - {}", err
))
86 pub fn generate_csrf_key() -> Result
<(), Error
> {
88 let path
= PathBuf
::from(configdir
!("/csrf.key"));
90 if path
.exists() { return Ok(()); }
92 let rsa
= Rsa
::generate(2048).unwrap();
94 let pem
= rsa
.private_key_to_pem()?
;
96 use nix
::sys
::stat
::Mode
;
98 let backup_user
= crate::backup
::backup_user()?
;
104 .perm(Mode
::from_bits_truncate(0o0640))
105 .owner(nix
::unistd
::ROOT
)
106 .group(backup_user
.gid
),
112 pub fn generate_auth_key() -> Result
<(), Error
> {
114 let priv_path
= PathBuf
::from(configdir
!("/authkey.key"));
116 let mut public_path
= priv_path
.clone();
117 public_path
.set_extension("pub");
119 if priv_path
.exists() && public_path
.exists() { return Ok(()); }
121 let rsa
= Rsa
::generate(4096).unwrap();
123 let priv_pem
= rsa
.private_key_to_pem()?
;
125 use nix
::sys
::stat
::Mode
;
128 &priv_path
, &priv_pem
, CreateOptions
::new().perm(Mode
::from_bits_truncate(0o0600)))?
;
130 let public_pem
= rsa
.public_key_to_pem()?
;
132 let backup_user
= crate::backup
::backup_user()?
;
138 .perm(Mode
::from_bits_truncate(0o0640))
139 .owner(nix
::unistd
::ROOT
)
140 .group(backup_user
.gid
),
146 pub fn csrf_secret() -> &'
static [u8] {
149 static ref SECRET
: Vec
<u8> =
150 file_get_contents(configdir
!("/csrf.key")).unwrap();
156 fn load_private_auth_key() -> Result
<PKey
<Private
>, Error
> {
158 let pem
= file_get_contents(configdir
!("/authkey.key"))?
;
159 let rsa
= Rsa
::private_key_from_pem(&pem
)?
;
160 let key
= PKey
::from_rsa(rsa
)?
;
165 pub fn private_auth_key() -> &'
static PKey
<Private
> {
168 static ref KEY
: PKey
<Private
> = load_private_auth_key().unwrap();
174 fn load_public_auth_key() -> Result
<PKey
<Public
>, Error
> {
176 let pem
= file_get_contents(configdir
!("/authkey.pub"))?
;
177 let rsa
= Rsa
::public_key_from_pem(&pem
)?
;
178 let key
= PKey
::from_rsa(rsa
)?
;
183 pub fn public_auth_key() -> &'
static PKey
<Public
> {
186 static ref KEY
: PKey
<Public
> = load_public_auth_key().unwrap();