]>
git.proxmox.com Git - proxmox.git/blob - proxmox-acme/src/jws.rs
1 use std
::convert
::TryFrom
;
3 use openssl
::hash
::{Hasher, MessageDigest}
;
4 use openssl
::pkey
::{HasPrivate, PKeyRef}
;
5 use openssl
::sign
::Signer
;
9 use crate::key
::{Jwk, PublicKey}
;
12 #[derive(Debug, Serialize)]
13 #[serde(rename_all = "camelCase")]
14 pub struct Protected
{
22 /// Acme requires to the use of *either* `jwk` *or* `kid` depending on the action taken.
23 #[derive(Debug, Serialize)]
24 #[serde(rename_all = "camelCase")]
26 /// This is the actual JWK structure.
29 /// This should be the account location.
33 #[derive(Debug, Serialize)]
34 #[serde(rename_all = "camelCase")]
44 location
: Option
<String
>,
48 ) -> Result
<Self, Error
>
58 b64u
::encode(serde_json
::to_string(payload
)?
.as_bytes()),
62 pub fn new_full
<P
: HasPrivate
>(
64 location
: Option
<String
>,
68 ) -> Result
<Self, Error
> {
69 let jwk
= Jwk
::try_from(key
)?
;
71 let pubkey
= jwk
.key
.clone();
72 let mut protected
= Protected
{
77 Some(location
) => KeyId
::Kid(location
),
78 None
=> KeyId
::Jwk(jwk
),
82 let (digest
, ec_order_bytes
): (MessageDigest
, usize) = match &pubkey
{
83 PublicKey
::Rsa(_
) => (Self::prepare_rsa(key
, &mut protected
), 0),
84 PublicKey
::Ec(_
) => Self::prepare_ec(key
, &mut protected
),
87 let protected_data
= b64u
::encode(serde_json
::to_string(&protected
)?
.as_bytes());
90 let prot
= protected_data
.as_bytes();
91 let payload
= payload
.as_bytes();
93 PublicKey
::Rsa(_
) => Self::sign_rsa(key
, digest
, prot
, payload
),
94 PublicKey
::Ec(_
) => Self::sign_ec(key
, digest
, ec_order_bytes
, prot
, payload
),
98 let signature
= b64u
::encode(&signature
);
101 protected
: protected_data
,
107 fn prepare_rsa
<P
>(_key
: &PKeyRef
<P
>, protected
: &mut Protected
) -> MessageDigest
111 protected
.alg
= "RS256";
112 MessageDigest
::sha256()
115 /// Returns the digest and the size of the two signature components 'r' and 's'.
116 fn prepare_ec
<P
>(_key
: &PKeyRef
<P
>, protected
: &mut Protected
) -> (MessageDigest
, usize)
120 // Note: if we support >256 bit keys we'll want to also support using ES512 here probably
121 protected
.alg
= "ES256";
122 // 'r' and 's' are each 256 bit numbers:
123 (MessageDigest
::sha256(), 32)
128 digest
: MessageDigest
,
131 ) -> Result
<Vec
<u8>, Error
>
135 let mut signer
= Signer
::new(digest
, key
)?
;
136 signer
.set_rsa_padding(openssl
::rsa
::Padding
::PKCS1
)?
;
137 signer
.update(protected
)?
;
138 signer
.update(b
".")?
;
139 signer
.update(payload
)?
;
140 Ok(signer
.sign_to_vec()?
)
145 digest
: MessageDigest
,
146 ec_order_bytes
: usize,
149 ) -> Result
<Vec
<u8>, Error
>
153 let mut hasher
= Hasher
::new(digest
)?
;
154 hasher
.update(protected
)?
;
155 hasher
.update(b
".")?
;
156 hasher
.update(payload
)?
;
158 openssl
::ecdsa
::EcdsaSig
::sign(hasher
.finish()?
.as_ref(), key
.ec_key()?
.as_ref())?
;
159 let r
= sig
.r().to_vec();
160 let s
= sig
.s().to_vec();
161 let mut out
= Vec
::with_capacity(ec_order_bytes
* 2);
162 out
.extend(std
::iter
::repeat(0u8).take(ec_order_bytes
- r
.len()));
164 out
.extend(std
::iter
::repeat(0u8).take(ec_order_bytes
- s
.len()));