bjorn/acme/
processing.rs

1use diesel::prelude::*;
2use std::convert::TryInto;
3
4pub type OrderClient = crate::cert_order::ca_client::CaClient<tonic::transport::Channel>;
5
6pub(crate) async fn verify_eab(
7    client: &mut OrderClient, eab: &crate::types::jose::FlattenedJWS, req_url: &str,
8    acct_key: &openssl::pkey::PKeyRef<openssl::pkey::Public>,
9) -> super::ACMEResult<String> {
10    let (eab_header, eab_payload_bytes, eab_signature_bytes) = match super::jws::start_decode_jws(&eab) {
11        Ok(v) => v,
12        Err(e) => return Err(e.1)
13    };
14
15    if eab_header.nonce.is_some() {
16        return Err(crate::types::error::Error {
17            error_type: crate::types::error::Type::Malformed,
18            status: 400,
19            title: "Bad request".to_string(),
20            detail: "EAB must not contain a nonce".to_string(),
21            sub_problems: vec![],
22            instance: None,
23            identifier: None,
24        });
25    }
26
27    if eab_header.url != req_url {
28        return Err(crate::types::error::Error {
29            error_type: crate::types::error::Type::Malformed,
30            status: 400,
31            title: "Bad request".to_string(),
32            detail: "EAB URL must match outer URL".to_string(),
33            sub_problems: vec![],
34            instance: None,
35            identifier: None,
36        });
37    }
38
39    let eab_id = match eab_header.key {
40        crate::types::jose::JWKKey::KID(i) => i,
41        _ => return Err(crate::types::error::Error {
42            error_type: crate::types::error::Type::Malformed,
43            status: 400,
44            title: "Bad request".to_string(),
45            detail: "EAB must contain KID".to_string(),
46            sub_problems: vec![],
47            instance: None,
48            identifier: None,
49        })
50    };
51
52    let eab_jwk: openssl::pkey::PKey<openssl::pkey::Public> = (
53        &serde_json::from_slice::<crate::types::jose::JWK>(&eab_payload_bytes)
54            .map_err(|err| crate::types::error::Error {
55                error_type: crate::types::error::Type::Malformed,
56                status: 400,
57                title: "Invalid JWK".to_string(),
58                detail: format!("Invalid JWK header: '{}'", err),
59                sub_problems: vec![],
60                instance: None,
61                identifier: None,
62            })?
63    ).try_into().map_err(|err| crate::types::error::Error {
64        error_type: crate::types::error::Type::BadPublicKey,
65        status: 400,
66        title: "Invalid public key".to_string(),
67        detail: err,
68        sub_problems: vec![],
69        instance: None,
70        identifier: None,
71    })?;
72
73    if !acct_key.public_eq(&eab_jwk) {
74        return Err(crate::types::error::Error {
75            error_type: crate::types::error::Type::Malformed,
76            status: 400,
77            title: "Bad request".to_string(),
78            detail: "EAB key must match outer key".to_string(),
79            sub_problems: vec![],
80            instance: None,
81            identifier: None,
82        });
83    }
84
85    let signature_method: i32 = match eab_header.alg.as_str() {
86        "HS256" => crate::cert_order::EabSignatureMethod::Hs256.into(),
87        "HS384" => crate::cert_order::EabSignatureMethod::Hs384.into(),
88        "HS512" => crate::cert_order::EabSignatureMethod::Hs512.into(),
89        "HS1" => crate::cert_order::EabSignatureMethod::Hs1.into(),
90        _ => return Err(crate::types::error::Error {
91            error_type: crate::types::error::Type::BadSignatureAlgorithm,
92            status: 400,
93            title: "Bad request".to_string(),
94            detail: "Invalid EAB signature algorithm".to_string(),
95            sub_problems: vec![],
96            instance: None,
97            identifier: None,
98        })
99    };
100
101    let eab_result = crate::try_db_result!(client.validate_eab(crate::cert_order::ValidateEabRequest {
102            kid: eab_id.clone(),
103            signature_method,
104            signed_data: format!("{}.{}", eab.protected, eab.payload).into_bytes(),
105            signature: eab_signature_bytes,
106        }).await, "Failed to check EAB: {}")?;
107
108    if !eab_result.get_ref().valid {
109        return Err(crate::types::error::Error {
110            error_type: crate::types::error::Type::Malformed,
111            status: 403,
112            title: "Forbidden".to_string(),
113            detail: "EAB signature did not verify".to_string(),
114            sub_problems: vec![],
115            instance: None,
116            identifier: None,
117        });
118    }
119
120    Ok(eab_id)
121}
122
123pub(crate) fn map_rpc_identifier(i: crate::cert_order::Identifier) -> crate::types::identifier::Identifier {
124    crate::types::identifier::Identifier {
125        id_type: match crate::cert_order::IdentifierType::try_from(i.id_type) {
126            Err(_) => "".to_string(),
127            Ok(crate::cert_order::IdentifierType::UnknownIdentifier) => "".to_string(),
128            Ok(crate::cert_order::IdentifierType::DnsIdentifier) => crate::types::identifier::Type::DNS.to_string(),
129            Ok(crate::cert_order::IdentifierType::IpIdentifier) => crate::types::identifier::Type::IP.to_string(),
130            Ok(crate::cert_order::IdentifierType::EmailIdentifier) => crate::types::identifier::Type::Email.to_string(),
131        },
132        value: i.identifier,
133    }
134}
135
136pub(crate) fn rpc_error_to_problem(err: crate::cert_order::Error) -> crate::types::error::Error {
137    crate::types::error::Error {
138        error_type: match crate::cert_order::ErrorType::try_from(err.error_type) {
139            Err(_) => crate::types::error::Type::ServerInternal,
140            Ok(crate::cert_order::ErrorType::ServerInternalError) => crate::types::error::Type::ServerInternal,
141            Ok(crate::cert_order::ErrorType::AccountDoesNotExistError) => crate::types::error::Type::AccountDoesNotExist,
142            Ok(crate::cert_order::ErrorType::AlreadyRevokedError) => crate::types::error::Type::AlreadyRevoked,
143            Ok(crate::cert_order::ErrorType::BadCsrError) => crate::types::error::Type::BadCSR,
144            Ok(crate::cert_order::ErrorType::BadNonceError) => crate::types::error::Type::BadNonce,
145            Ok(crate::cert_order::ErrorType::BadPublicKeyError) => crate::types::error::Type::BadPublicKey,
146            Ok(crate::cert_order::ErrorType::BadRevocationReasonError) => crate::types::error::Type::BadRevocationReason,
147            Ok(crate::cert_order::ErrorType::BadSignatureAlgorithmError) => crate::types::error::Type::BadSignatureAlgorithm,
148            Ok(crate::cert_order::ErrorType::CaaError) => crate::types::error::Type::CAA,
149            Ok(crate::cert_order::ErrorType::CompoundError) => crate::types::error::Type::Compound,
150            Ok(crate::cert_order::ErrorType::ConnectionError) => crate::types::error::Type::Connection,
151            Ok(crate::cert_order::ErrorType::DnsError) => crate::types::error::Type::DNS,
152            Ok(crate::cert_order::ErrorType::ExternalAccountRequiredError) => crate::types::error::Type::ExternalAccountRequired,
153            Ok(crate::cert_order::ErrorType::IncorrectResponseError) => crate::types::error::Type::IncorrectResponse,
154            Ok(crate::cert_order::ErrorType::InvalidContactError) => crate::types::error::Type::InvalidContact,
155            Ok(crate::cert_order::ErrorType::MalformedError) => crate::types::error::Type::Malformed,
156            Ok(crate::cert_order::ErrorType::OrderNotReadyError) => crate::types::error::Type::OrderNotReady,
157            Ok(crate::cert_order::ErrorType::RateLimitedError) => crate::types::error::Type::RateLimited,
158            Ok(crate::cert_order::ErrorType::RejectedIdentifierError) => crate::types::error::Type::RejectedIdentifier,
159            Ok(crate::cert_order::ErrorType::TlsError) => crate::types::error::Type::TLS,
160            Ok(crate::cert_order::ErrorType::UnauthorizedError) => crate::types::error::Type::Unauthorized,
161            Ok(crate::cert_order::ErrorType::UnsupportedContactError) => crate::types::error::Type::UnsupportedContact,
162            Ok(crate::cert_order::ErrorType::UnsupportedIdentifierError) => crate::types::error::Type::UnsupportedIdentifier,
163            Ok(crate::cert_order::ErrorType::UserActionRequiredError) => crate::types::error::Type::UserActionRequired,
164            Ok(crate::cert_order::ErrorType::AutoRenewalCanceledError) => crate::types::error::Type::AutoRenewalCanceled,
165            Ok(crate::cert_order::ErrorType::AutoRenewalExpiredError) => crate::types::error::Type::AutoRenewalExpired,
166            Ok(crate::cert_order::ErrorType::AutoRenewalCancellationInvalidError) => crate::types::error::Type::AutoRenewalCancellationInvalid,
167            Ok(crate::cert_order::ErrorType::AutoRenewalRevocationNotSupportedError) => crate::types::error::Type::AutoRenewalRevocationNotSupported,
168        },
169        title: err.title,
170        status: err.status as u16,
171        detail: err.detail,
172        instance: err.instance,
173        sub_problems: err.sub_problems.into_iter().map(rpc_error_to_problem).collect(),
174        identifier: err.identifier.map(map_rpc_identifier),
175    }
176}
177
178pub(crate) fn unwrap_order_response(resp: crate::cert_order::OrderResponse) -> crate::acme::ACMEResult<crate::cert_order::Order> {
179    match resp.result {
180        Some(crate::cert_order::order_response::Result::Order(o)) => Ok(o),
181        Some(crate::cert_order::order_response::Result::Error(e)) => Err(
182            crate::util::error_list_to_result(
183                e.errors.into_iter().map(rpc_error_to_problem).collect(),
184                "Multiple errors make this order invalid".to_string(),
185            ).err().unwrap()
186        ),
187        None => Err(crate::internal_server_error!())
188    }
189}
190
191pub(crate) fn unwrap_authz_response(resp: crate::cert_order::AuthorizationResponse) -> crate::acme::ACMEResult<crate::cert_order::Authorization> {
192    match resp.result {
193        Some(crate::cert_order::authorization_response::Result::Authorization(a)) => Ok(a),
194        Some(crate::cert_order::authorization_response::Result::Error(e)) => Err(
195            crate::util::error_list_to_result(
196                e.errors.into_iter().map(rpc_error_to_problem).collect(),
197                "Multiple errors make this authorization invalid".to_string(),
198            ).err().unwrap()
199        ),
200        None => Err(crate::internal_server_error!())
201    }
202}
203
204pub(crate) fn unwrap_chall_response(resp: crate::cert_order::ChallengeResponse) -> crate::acme::ACMEResult<crate::cert_order::Challenge> {
205    match resp.result {
206        Some(crate::cert_order::challenge_response::Result::Challenge(a)) => Ok(a),
207        Some(crate::cert_order::challenge_response::Result::Error(e)) => Err(
208            crate::util::error_list_to_result(
209                e.errors.into_iter().map(rpc_error_to_problem).collect(),
210                "Multiple errors make this challenge invalid".to_string(),
211            ).err().unwrap()
212        ),
213        None => Err(crate::internal_server_error!())
214    }
215}
216
217pub(crate) async fn create_order(
218    client: &mut OrderClient, db: &crate::DBConn,
219    order: &crate::types::order::OrderCreate, account: &crate::acme::Account,
220) -> crate::acme::ACMEResult<(super::models::Order, crate::cert_order::Order)> {
221    let mut errors = vec![];
222
223    let mut identifiers = vec![];
224
225    for id in &order.identifiers {
226        let id_type = crate::types::identifier::Type::from_str(&id.id_type);
227        let grpc_id_type = match id_type {
228            Some(crate::types::identifier::Type::DNS) => crate::cert_order::IdentifierType::DnsIdentifier,
229            Some(crate::types::identifier::Type::IP) => crate::cert_order::IdentifierType::IpIdentifier,
230            Some(crate::types::identifier::Type::Email) => crate::cert_order::IdentifierType::EmailIdentifier,
231            None => {
232                errors.push(crate::types::error::Error {
233                    error_type: crate::types::error::Type::UnsupportedIdentifier,
234                    status: 400,
235                    title: "Unsupported identifier".to_string(),
236                    detail: format!("'{}' is not an identifier we support", id.id_type),
237                    sub_problems: vec![],
238                    instance: None,
239                    identifier: Some(id.to_owned()),
240                });
241                continue;
242            }
243        };
244        identifiers.push(crate::cert_order::Identifier {
245            id_type: grpc_id_type.into(),
246            identifier: id.value.clone(),
247        });
248    }
249
250    crate::util::error_list_to_result(errors, "Multiple errors make this order invalid".to_string())?;
251
252    let order_result = crate::try_db_result!(client.create_order(crate::cert_order::CreateOrderRequest {
253        identifiers,
254        not_before: crate::util::chrono_to_proto(order.not_before),
255        not_after: crate::util::chrono_to_proto(order.not_after),
256        account_id: account.inner.id.to_string(),
257        eab_id: account.inner.eab_id.clone(),
258    }).await, "Failed to create order: {}")?;
259
260    let ca_order = unwrap_order_response(order_result.into_inner())?;
261
262    let db_order = super::models::Order {
263        id: uuid::Uuid::new_v4(),
264        account: account.inner.id,
265        ca_id: ca_order.id.clone(),
266    };
267
268    let db_order = crate::try_db_result!(db.run(move |c|
269        diesel::insert_into(super::schema::orders::dsl::orders)
270            .values(&db_order).get_result(c)
271    ).await,
272        "Unable to save order to database: {}"
273    )?;
274
275    Ok((db_order, ca_order))
276}
277
278pub(crate) async fn create_authz(
279    client: &mut OrderClient, db: &crate::DBConn,
280    authz: &crate::types::authorization::AuthorizationCreate, account: &crate::acme::Account,
281) -> crate::acme::ACMEResult<(super::models::Authorization, crate::cert_order::Authorization)> {
282    let grpc_id_type = match crate::types::identifier::Type::from_str(&authz.identifier.id_type) {
283        Some(crate::types::identifier::Type::DNS) => crate::cert_order::IdentifierType::DnsIdentifier,
284        Some(crate::types::identifier::Type::IP) => crate::cert_order::IdentifierType::IpIdentifier,
285        Some(crate::types::identifier::Type::Email) => crate::cert_order::IdentifierType::EmailIdentifier,
286        None => {
287            return Err(crate::types::error::Error {
288                error_type: crate::types::error::Type::UnsupportedIdentifier,
289                status: 400,
290                title: "Unsupported identifier".to_string(),
291                detail: format!("'{}' is not an identifier we support", authz.identifier.id_type),
292                sub_problems: vec![],
293                instance: None,
294                identifier: Some(authz.identifier.to_owned()),
295            });
296        }
297    };
298    let identifier = crate::cert_order::Identifier {
299        id_type: grpc_id_type.into(),
300        identifier: authz.identifier.value.clone(),
301    };
302
303    let authz_result = crate::try_db_result!(client.create_authorization(crate::cert_order::CreateAuthorizationRequest {
304        identifier: Some(identifier),
305        account_id: account.inner.id.to_string(),
306        eab_id: account.inner.eab_id.clone(),
307    }).await, "Failed to create authorization: {}")?;
308
309    let ca_authz = unwrap_authz_response(authz_result.into_inner())?;
310
311    let db_authz = super::models::Authorization {
312        id: uuid::Uuid::new_v4(),
313        account: account.inner.id,
314        ca_id: ca_authz.id.clone(),
315    };
316
317    let db_authz = crate::try_db_result!(db.run(move |c|
318        diesel::insert_into(super::schema::authorizations::dsl::authorizations)
319            .values(&db_authz).get_result(c)
320    ).await,
321        "Unable to save authorization to database: {}"
322    )?;
323
324    Ok((db_authz, ca_authz))
325}