]> git.proxmox.com Git - proxmox.git/blob - proxmox-acme/src/eab.rs
move to proxmox-acme
[proxmox.git] / proxmox-acme / src / eab.rs
1 use openssl::hash::MessageDigest;
2 use openssl::pkey::{HasPrivate, PKeyRef};
3 use openssl::sign::Signer;
4 use serde::{Deserialize, Serialize};
5
6 use crate::key::Jwk;
7 use crate::{b64u, Error};
8
9 #[derive(Debug, Serialize)]
10 #[serde(rename_all = "camelCase")]
11 struct Protected {
12 alg: &'static str,
13 url: String,
14 kid: String,
15 }
16
17 #[derive(Debug, Serialize, Deserialize, Clone)]
18 #[serde(rename_all = "camelCase")]
19 pub struct ExternalAccountBinding {
20 protected: String,
21 payload: String,
22 signature: String,
23 }
24
25 impl ExternalAccountBinding {
26 pub fn new<P>(
27 eab_kid: &str,
28 eab_hmac_key: &PKeyRef<P>,
29 jwk: Jwk,
30 url: String,
31 ) -> Result<Self, Error>
32 where
33 P: HasPrivate,
34 {
35 let protected = Protected {
36 alg: "HS256",
37 kid: eab_kid.to_string(),
38 url,
39 };
40 let payload = b64u::encode(serde_json::to_string(&jwk)?.as_bytes());
41 let protected_data = b64u::encode(serde_json::to_string(&protected)?.as_bytes());
42 let signature = {
43 let protected = protected_data.as_bytes();
44 let payload = payload.as_bytes();
45 Self::sign_hmac(eab_hmac_key, protected, payload)?
46 };
47
48 let signature = b64u::encode(&signature);
49 Ok(ExternalAccountBinding {
50 protected: protected_data,
51 payload,
52 signature,
53 })
54 }
55
56 fn sign_hmac<P>(key: &PKeyRef<P>, protected: &[u8], payload: &[u8]) -> Result<Vec<u8>, Error>
57 where
58 P: HasPrivate,
59 {
60 let mut signer = Signer::new(MessageDigest::sha256(), key)?;
61 signer.update(protected)?;
62 signer.update(b".")?;
63 signer.update(payload)?;
64 Ok(signer.sign_to_vec()?)
65 }
66 }