1use foreign_types::{ForeignType, ForeignTypeRef};
2use std::convert::TryFrom;
3use http_body_util::BodyExt;
4use base64::prelude::*;
5
6pub mod caa;
7
8#[derive(Debug)]
9pub enum Identifier {
10 Domain(String, bool),
11 IPAddr(std::net::IpAddr),
12 Email(String),
13}
14
15fn map_identifier(identifier: Option<crate::cert_order::Identifier>) -> Result<Identifier, tonic::Status> {
16 if let Some(identifier) = identifier {
17 Ok(match crate::cert_order::IdentifierType::try_from(identifier.id_type) {
18 Ok(crate::cert_order::IdentifierType::DnsIdentifier) => {
19 let is_wild = identifier.identifier.starts_with("*.");
20 if is_wild {
21 Identifier::Domain(identifier.identifier[2..].to_string(), true)
22 } else {
23 Identifier::Domain(identifier.identifier, false)
24 }
25 }
26 Ok(crate::cert_order::IdentifierType::IpIdentifier) => {
27 let ip_addr: std::net::IpAddr = match std::str::FromStr::from_str(&identifier.identifier) {
28 Ok(a) => a,
29 Err(_) => return Err(tonic::Status::invalid_argument("Invalid IP address")),
30 };
31 Identifier::IPAddr(ip_addr)
32 }
33 Ok(crate::cert_order::IdentifierType::EmailIdentifier) => {
34 Identifier::Email(identifier.identifier)
35 },
36 _ => return Err(tonic::Status::invalid_argument("Invalid identifier type specified")),
37 })
38 } else {
39 Err(tonic::Status::invalid_argument("Identifier must be specified"))
40 }
41}
42
43impl Identifier {
44 fn to_pb(&self) -> crate::cert_order::Identifier {
45 match self {
46 Identifier::Domain(d, _) => crate::cert_order::Identifier {
47 id_type: crate::cert_order::IdentifierType::DnsIdentifier.into(),
48 identifier: d.clone(),
49 },
50 Identifier::IPAddr(ip) => crate::cert_order::Identifier {
51 id_type: crate::cert_order::IdentifierType::IpIdentifier.into(),
52 identifier: ip.to_string(),
53 },
54 Identifier::Email(e) => crate::cert_order::Identifier {
55 id_type: crate::cert_order::IdentifierType::EmailIdentifier.into(),
56 identifier: e.clone(),
57 }
58 }
59 }
60}
61
62#[derive(Debug)]
63pub struct Validator<S: torrosion::storage::Storage> {
64 dns_resolver: trust_dns_resolver::TokioAsyncResolver,
65 reqwest_client: reqwest::Client,
66 tor_client: Option<torrosion::Client<S>>,
67 caa_identities: Vec<String>,
68}
69
70impl<S: torrosion::storage::Storage + Send + Sync + 'static> Validator<S> {
71 pub async fn new(caa_identities: Vec<String>, storage: Option<S>) -> Self {
72 let resolver = trust_dns_resolver::AsyncResolver::tokio_from_system_conf()
73 .expect("Unable to read DNS config");
74 let client = reqwest::Client::builder()
75 .user_agent(concat!(env!("CARGO_PKG_NAME"), " ", env!("CARGO_PKG_VERSION")))
76 .gzip(true)
77 .brotli(true)
78 .deflate(true)
79 .redirect(reqwest::redirect::Policy::limited(10))
80 .referer(true)
81 .no_proxy()
82 .build()
83 .expect("Unable to build HTTP client");
84
85 let tor_client = if let Some(storage) = storage {
86 let mut c = torrosion::Client::new(storage);
87 c.run().await;
88
89 Some(c)
90 } else {
91 None
92 };
93
94 Validator {
95 dns_resolver: resolver,
96 reqwest_client: client,
97 tor_client,
98 caa_identities,
99 }
100 }
101}
102
103async fn check_caa<S: torrosion::storage::Storage + Send + Sync + 'static>(
104 validator: &Validator<S>, identifier: &Identifier, validation_method: &str,
105 account_uri: Option<&str>, hs_priv_key: Option<&[u8; 32]>, onion_caa: Option<&crate::cert_order::OnionCaa>,
106) -> crate::cert_order::ValidationResult {
107 let caa_res = match caa::verify_caa_record(
108 validator, identifier, validation_method, account_uri, hs_priv_key, onion_caa
109 ).await {
110 Ok(r) => r,
111 Err(err) => match err {
112 caa::CAAError::ServFail => return crate::cert_order::ValidationResult {
113 valid: false,
114 error: Some(crate::cert_order::ErrorResponse {
115 errors: vec![crate::cert_order::Error {
116 error_type: crate::cert_order::ErrorType::DnsError.into(),
117 title: "CAA error".to_string(),
118 detail: "SERVFAIL when checking CAA record".to_string(),
119 status: 400,
120 identifier: Some(identifier.to_pb()),
121 instance: None,
122 sub_problems: vec![],
123 }]
124 }),
125 },
126 caa::CAAError::UnsupportedCritical(e) => return crate::cert_order::ValidationResult {
127 valid: false,
128 error: Some(crate::cert_order::ErrorResponse {
129 errors: vec![crate::cert_order::Error {
130 error_type: crate::cert_order::ErrorType::CaaError.into(),
131 title: "CAA error".to_string(),
132 detail: format!("Unsupported critical CAA record: {}", e),
133 status: 400,
134 identifier: Some(identifier.to_pb()),
135 instance: None,
136 sub_problems: vec![],
137 }]
138 }),
139 },
140 caa::CAAError::Other(e) => return crate::cert_order::ValidationResult {
141 valid: false,
142 error: Some(crate::cert_order::ErrorResponse {
143 errors: vec![crate::cert_order::Error {
144 error_type: crate::cert_order::ErrorType::CaaError.into(),
145 title: "CAA error".to_string(),
146 detail: e,
147 status: 400,
148 identifier: Some(identifier.to_pb()),
149 instance: None,
150 sub_problems: vec![],
151 }]
152 }),
153 },
154 }
155 };
156
157 if caa_res {
158 crate::cert_order::ValidationResult {
159 valid: true,
160 error: None,
161 }
162 } else {
163 crate::cert_order::ValidationResult {
164 valid: false,
165 error: Some(crate::cert_order::ErrorResponse {
166 errors: vec![crate::cert_order::Error {
167 error_type: crate::cert_order::ErrorType::CaaError.into(),
168 title: "CAA error".to_string(),
169 detail: "CAA policy prohibits issuance".to_string(),
170 status: 400,
171 identifier: Some(identifier.to_pb()),
172 instance: None,
173 sub_problems: vec![],
174 }]
175 }),
176 }
177 }
178}
179
180trait RW: tokio::io::AsyncRead + tokio::io::AsyncWrite {}
181impl<T> RW for T where T: tokio::io::AsyncRead + tokio::io::AsyncWrite {}
182
183#[tonic::async_trait]
184impl<S: torrosion::storage::Storage + Send + Sync + 'static> crate::cert_order::validator_server::Validator for Validator<S> {
185 async fn check_caa(
186 &self, request: tonic::Request<crate::cert_order::CaaCheckRequest>,
187 ) -> Result<tonic::Response<crate::cert_order::ValidationResult>, tonic::Status> {
188 let req = request.into_inner();
189 let identifier = map_identifier(req.identifier.clone())?;
190
191 let hs_priv_key = if req.hs_private_key.len() == 0 {
192 None
193 } else if req.hs_private_key.len() == 32 {
194 Some(std::convert::TryInto::<[u8; 32]>::try_into(req.hs_private_key.as_slice()).unwrap())
195 } else {
196 return Err(tonic::Status::invalid_argument("hs_priv_key must be 32 bytes long"));
197 };
198
199 let validation_method = match crate::cert_order::ValidationMethod::try_from(req.validation_method) {
200 Ok(crate::cert_order::ValidationMethod::Http01) => "http-01",
201 Ok(crate::cert_order::ValidationMethod::Dns01) => "dns-01",
202 Ok(crate::cert_order::ValidationMethod::TlsAlpn01) => "tls-alpn-01",
203 Ok(crate::cert_order::ValidationMethod::OnionCsr01) => "onion-csr-01",
204 _ => return Err(tonic::Status::invalid_argument("Invalid validation method specified")),
205 };
206
207 Ok(tonic::Response::new( check_caa(
208 self, &identifier, validation_method,
209 req.account_uri.as_deref(), hs_priv_key.as_ref(),
210 req.onion_caa.as_ref()
211 ).await))
212 }
213
214 async fn validate_http01(
215 &self, request: tonic::Request<crate::cert_order::KeyValidationRequest>,
216 ) -> Result<tonic::Response<crate::cert_order::ValidationResult>, tonic::Status> {
217 let req = request.into_inner();
218 let identifier = map_identifier(req.identifier.clone())?;
219
220 let hs_priv_key = if req.hs_private_key.len() == 0 {
221 None
222 } else if req.hs_private_key.len() == 32 {
223 Some(std::convert::TryInto::<[u8; 32]>::try_into(req.hs_private_key.as_slice()).unwrap())
224 } else {
225 return Err(tonic::Status::invalid_argument("hs_priv_key must be 32 bytes long"));
226 };
227
228 let (test_uri, is_tor) = match identifier {
229 Identifier::Domain(domain, wildcard) => {
230 if wildcard {
231 return Err(tonic::Status::invalid_argument("http-01 must not be used for wildcard domains"));
232 }
233
234 (format!("http://{}:80/.well-known/acme-challenge/{}", domain, req.token), domain.ends_with(".onion"))
235 },
236 Identifier::IPAddr(ip) => (match ip {
237 std::net::IpAddr::V4(ipv4) => format!("http://{}:80/.well-known/acme-challenge/{}", ipv4, req.token),
238 std::net::IpAddr::V6(ipv6) => format!("http://[{}]:80/.well-known/acme-challenge/{}", ipv6, req.token),
239 }, false),
240 Identifier::Email(_) => return Err(tonic::Status::invalid_argument("http-01 makes no sense for email"))
241 };
242 let key_auth = format!("{}.{}", req.token, req.account_thumbprint);
243
244 let uri_error = crate::cert_order::ErrorResponse {
245 errors: vec![crate::cert_order::Error {
246 error_type: crate::cert_order::ErrorType::ConnectionError.into(),
247 title: "Validation failed".to_string(),
248 detail: "Invalid URI".to_string(),
249 status: 400,
250 identifier: req.identifier.clone(),
251 instance: None,
252 sub_problems: vec![],
253 }]
254 };
255 let timeout_error = crate::cert_order::ErrorResponse {
256 errors: vec![crate::cert_order::Error {
257 error_type: crate::cert_order::ErrorType::ConnectionError.into(),
258 title: "Validation failed".to_string(),
259 detail: "Connection timed out".to_string(),
260 status: 400,
261 identifier: req.identifier.clone(),
262 instance: None,
263 sub_problems: vec![],
264 }]
265 };
266 let connect_error = crate::cert_order::ErrorResponse {
267 errors: vec![crate::cert_order::Error {
268 error_type: crate::cert_order::ErrorType::ConnectionError.into(),
269 title: "Validation failed".to_string(),
270 detail: "Connection refused".to_string(),
271 status: 400,
272 identifier: req.identifier.clone(),
273 instance: None,
274 sub_problems: vec![],
275 }]
276 };
277 let other_error = crate::cert_order::ErrorResponse {
278 errors: vec![crate::cert_order::Error {
279 error_type: crate::cert_order::ErrorType::ConnectionError.into(),
280 title: "Validation failed".to_string(),
281 detail: "Unknown request error".to_string(),
282 status: 400,
283 identifier: req.identifier.clone(),
284 instance: None,
285 sub_problems: vec![],
286 }]
287 };
288 let charset_error = crate::cert_order::ErrorResponse {
289 errors: vec![crate::cert_order::Error {
290 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
291 title: "Validation failed".to_string(),
292 detail: "Text charset error".to_string(),
293 status: 400,
294 identifier: req.identifier.clone(),
295 instance: None,
296 sub_problems: vec![],
297 }]
298 };
299
300 let (status, resp_txt) = if is_tor {
301 let client = match self.tor_client {
302 Some(ref c) => c.clone(),
303 None => return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
304 valid: false,
305 error: Some(crate::cert_order::ErrorResponse {
306 errors: vec![crate::cert_order::Error {
307 error_type: crate::cert_order::ErrorType::UnsupportedIdentifierError.into(),
308 title: "Validation failed".to_string(),
309 detail: "Hidden services are not supported".to_string(),
310 status: 400,
311 identifier: req.identifier,
312 instance: None,
313 sub_problems: vec![],
314 }]
315 }),
316 }))
317 };
318
319 let test_uri = match hyper::Uri::try_from(&test_uri) {
320 Ok(u) => u,
321 Err(_) => return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
322 valid: false,
323 error: Some(uri_error),
324 }))
325 };
326
327 let hs_client = torrosion::hs::http::new_hs_client(client, hs_priv_key);
328
329 let resp = match hs_client.get(test_uri).await {
330 Ok(u) => u,
331 Err(err) => {
332 debug!("Error connecting to hidden service validation endpoint: {}", err);
333 return if err.is_connect() {
334 Ok(tonic::Response::new(crate::cert_order::ValidationResult {
335 valid: false,
336 error: Some(connect_error),
337 }))
338 } else {
339 Ok(tonic::Response::new(crate::cert_order::ValidationResult {
340 valid: false,
341 error: Some(other_error),
342 }))
343 }
344 }
345 };
346
347 (resp.status(), match resp.collect().await {
348 Ok(b) => match String::from_utf8(b.to_bytes().to_vec()) {
349 Ok(s) => s,
350 Err(_) => return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
351 valid: false,
352 error: Some(charset_error),
353 }))
354 },
355 Err(_) => return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
356 valid: false,
357 error: Some(other_error),
358 }))
359 })
360 } else {
361 let test_uri = match reqwest::Url::parse(&test_uri) {
362 Ok(u) => u,
363 Err(_) => return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
364 valid: false,
365 error: Some(uri_error),
366 }))
367 };
368 let resp = match self.reqwest_client.get(test_uri).send().await {
369 Ok(u) => u,
370 Err(err) => {
371 debug!("Error connecting to validation endpoint: {}", err);
372 return if err.is_timeout() {
373 Ok(tonic::Response::new(crate::cert_order::ValidationResult {
374 valid: false,
375 error: Some(timeout_error),
376 }))
377 } else if err.is_connect() {
378 Ok(tonic::Response::new(crate::cert_order::ValidationResult {
379 valid: false,
380 error: Some(connect_error),
381 }))
382 } else if err.is_redirect() {
383 Ok(tonic::Response::new(crate::cert_order::ValidationResult {
384 valid: false,
385 error: Some(crate::cert_order::ErrorResponse {
386 errors: vec![crate::cert_order::Error {
387 error_type: crate::cert_order::ErrorType::ConnectionError.into(),
388 title: "Validation failed".to_string(),
389 detail: "Too many redirects".to_string(),
390 status: 400,
391 identifier: req.identifier,
392 instance: None,
393 sub_problems: vec![],
394 }]
395 }),
396 }))
397 } else {
398 Ok(tonic::Response::new(crate::cert_order::ValidationResult {
399 valid: false,
400 error: Some(other_error),
401 }))
402 }
403 }
404 };
405
406 (resp.status(), match resp.text().await {
407 Ok(t) => t,
408 Err(_) => return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
409 valid: false,
410 error: Some(charset_error),
411 }))
412 })
413 };
414
415 if !status.is_success() {
416 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
417 valid: false,
418 error: Some(crate::cert_order::ErrorResponse {
419 errors: vec![crate::cert_order::Error {
420 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
421 title: "Validation failed".to_string(),
422 detail: format!("HTTP {} received", status.as_str()),
423 status: 400,
424 identifier: req.identifier,
425 instance: None,
426 sub_problems: vec![],
427 }]
428 }),
429 }));
430 }
431
432 if resp_txt.trim() == key_auth {
433 Ok(tonic::Response::new(crate::cert_order::ValidationResult {
434 valid: true,
435 error: None,
436 }))
437 } else {
438 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
439 valid: false,
440 error: Some(crate::cert_order::ErrorResponse {
441 errors: vec![crate::cert_order::Error {
442 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
443 title: "Validation failed".to_string(),
444 detail: format!("Expected '{}', received '{}'", key_auth, resp_txt),
445 status: 400,
446 identifier: req.identifier,
447 instance: None,
448 sub_problems: vec![],
449 }]
450 }),
451 }));
452 }
453 }
454
455 async fn validate_dns01(
456 &self, request: tonic::Request<crate::cert_order::KeyValidationRequest>,
457 ) -> Result<tonic::Response<crate::cert_order::ValidationResult>, tonic::Status> {
458 let req = request.into_inner();
459 let identifier = map_identifier(req.identifier.clone())?;
460
461 let key_auth = format!("{}.{}", req.token, req.account_thumbprint);
462 let key_auth_hash_bytes = openssl::hash::hash(openssl::hash::MessageDigest::sha256(), key_auth.as_bytes()).unwrap().to_vec();
463 let key_auth_hash = BASE64_URL_SAFE_NO_PAD.encode(&key_auth_hash_bytes);
464 let key_auth_hash_utf8 = key_auth_hash.as_bytes();
465
466 let search_domain = match identifier {
467 Identifier::Domain(domain, _) => {
468 if domain.ends_with(".onion") {
469 return Err(tonic::Status::invalid_argument("dns-01 must not be used for .onion domains"))
470 }
471 format!("_acme-challenge.{}.", domain.trim_end_matches('.'))
472 },
473 Identifier::IPAddr(_) => return Err(tonic::Status::invalid_argument("dns-01 must not be used for IP addresses")),
474 Identifier::Email(_) => return Err(tonic::Status::invalid_argument("dns-01 makes no sense for email")),
475 };
476 match self.dns_resolver.txt_lookup(search_domain.clone()).await {
477 Ok(r) => {
478 for record in r.iter(){
479 if let Some(data) = record.txt_data().iter().next().as_deref() {
480 if data.as_ref() == key_auth_hash_utf8 {
481 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
482 valid: true,
483 error: None,
484 }));
485 }
486 }
487 }
488
489 Ok(tonic::Response::new(crate::cert_order::ValidationResult {
490 valid: false,
491 error: Some(crate::cert_order::ErrorResponse {
492 errors: vec![crate::cert_order::Error {
493 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
494 title: "Validation failed".to_string(),
495 detail: format!("No TXT records found for {} with the value '{}'", search_domain, key_auth_hash),
496 status: 400,
497 identifier: req.identifier,
498 instance: None,
499 sub_problems: vec![],
500 }]
501 }),
502 }))
503 }
504 Err(err) => match err.kind() {
505 trust_dns_resolver::error::ResolveErrorKind::NoRecordsFound { .. } => Ok(tonic::Response::new(crate::cert_order::ValidationResult {
506 valid: false,
507 error: Some(crate::cert_order::ErrorResponse {
508 errors: vec![crate::cert_order::Error {
509 error_type: crate::cert_order::ErrorType::DnsError.into(),
510 title: "Validation failed".to_string(),
511 detail: format!("No TXT records found for {}", search_domain),
512 status: 400,
513 identifier: req.identifier,
514 instance: None,
515 sub_problems: vec![],
516 }]
517 }),
518 })),
519 _ => Ok(tonic::Response::new(crate::cert_order::ValidationResult {
520 valid: false,
521 error: Some(crate::cert_order::ErrorResponse {
522 errors: vec![crate::cert_order::Error {
523 error_type: crate::cert_order::ErrorType::DnsError.into(),
524 title: "Validation failed".to_string(),
525 detail: format!("SERVFAIL whilst getting records for {}", search_domain),
526 status: 400,
527 identifier: req.identifier,
528 instance: None,
529 sub_problems: vec![],
530 }]
531 }),
532 }))
533 }
534 }
535 }
536
537 async fn validate_tlsalpn01(
538 &self, request: tonic::Request<crate::cert_order::KeyValidationRequest>,
539 ) -> Result<tonic::Response<crate::cert_order::ValidationResult>, tonic::Status> {
540 let req = request.into_inner();
541 let identifier = map_identifier(req.identifier.clone())?;
542
543 let hs_priv_key = if req.hs_private_key.len() == 0 {
544 None
545 } else if req.hs_private_key.len() == 32 {
546 Some(std::convert::TryInto::<[u8; 32]>::try_into(req.hs_private_key.as_slice()).unwrap())
547 } else {
548 return Err(tonic::Status::invalid_argument("hs_priv_key must be 32 bytes long"));
549 };
550
551 let (connection_string, sni_string, ip_bytes, is_tor) = match identifier {
552 Identifier::Domain(domain, wildcard) => {
553 if wildcard {
554 return Err(tonic::Status::invalid_argument("tls-alpn-01 must not be used for wildcard domains"));
555 }
556
557 (format!("{}:443", domain), domain.to_ascii_lowercase(), vec![], domain.ends_with(".onion"))
558 },
559 Identifier::IPAddr(ip) => match ip {
560 std::net::IpAddr::V4(ipv4) =>
561 (format!("{}:443", ipv4), trust_dns_resolver::Name::from(ipv4).to_ascii(), ipv4.octets().to_vec(), false),
562 std::net::IpAddr::V6(ipv6) =>
563 (format!("[{}]:443", ipv6), trust_dns_resolver::Name::from(ipv6).to_ascii(), ipv6.octets().to_vec(), false),
564 },
565 Identifier::Email(_) => return Err(tonic::Status::invalid_argument("tls-alpn-01 makes no sense for email"))
566 };
567 let key_auth = format!("{}.{}", req.token, req.account_thumbprint);
568 let key_auth_hash_bytes = openssl::hash::hash(openssl::hash::MessageDigest::sha256(), key_auth.as_bytes()).unwrap().to_vec();
569
570 let mut ssl_ctx_builder = match openssl::ssl::SslContext::builder(openssl::ssl::SslMethod::tls_client()) {
571 Ok(b) => b,
572 Err(err) => {
573 error!("Failed to create SSL context builder: {}", err);
574 return Err(tonic::Status::internal("failed to create SSL context"));
575 }
576 };
577 ssl_ctx_builder.set_verify(openssl::ssl::SslVerifyMode::NONE);
578 ssl_ctx_builder.set_min_proto_version(Some(openssl::ssl::SslVersion::TLS1_2)).unwrap();
579 ssl_ctx_builder.set_alpn_protos(b"\x0aacme-tls/1").unwrap();
580 let ssl_ctx = ssl_ctx_builder.build();
581
582 let tcp_stream: std::pin::Pin<Box<dyn RW + Send>> = if is_tor {
583 let client = match self.tor_client {
584 Some(ref c) => c,
585 None => return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
586 valid: false,
587 error: Some(crate::cert_order::ErrorResponse {
588 errors: vec![crate::cert_order::Error {
589 error_type: crate::cert_order::ErrorType::UnsupportedIdentifierError.into(),
590 title: "Validation failed".to_string(),
591 detail: "Hidden services are not supported".to_string(),
592 status: 400,
593 identifier: req.identifier,
594 instance: None,
595 sub_problems: vec![],
596 }]
597 }),
598 }))
599 };
600
601 let hs_address = match torrosion::hs::HSAddress::from_str(&sni_string) {
602 Ok(hs) => hs,
603 Err(_) => return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
604 valid: false,
605 error: Some(crate::cert_order::ErrorResponse {
606 errors: vec![crate::cert_order::Error {
607 error_type: crate::cert_order::ErrorType::ConnectionError.into(),
608 title: "Connection failed".to_string(),
609 detail: "Malformed HS address".to_string(),
610 status: 400,
611 identifier: req.identifier,
612 instance: None,
613 sub_problems: vec![],
614 }]
615 }),
616 }))
617 };
618
619 let (ds, subcred) = match hs_address.fetch_ds(&client, hs_priv_key).await {
620 Ok(v) => v,
621 Err(_) => return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
622 valid: false,
623 error: Some(crate::cert_order::ErrorResponse {
624 errors: vec![crate::cert_order::Error {
625 error_type: crate::cert_order::ErrorType::ConnectionError.into(),
626 title: "Connection failed".to_string(),
627 detail: "Failed to get HS descriptor".to_string(),
628 status: 400,
629 identifier: req.identifier,
630 instance: None,
631 sub_problems: vec![],
632 }]
633 }),
634 }))
635 };
636 let hs_circ = match torrosion::hs::con::connect(&client, &ds, &subcred).await {
637 Ok(v) => v,
638 Err(_) => return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
639 valid: false,
640 error: Some(crate::cert_order::ErrorResponse {
641 errors: vec![crate::cert_order::Error {
642 error_type: crate::cert_order::ErrorType::ConnectionError.into(),
643 title: "Connection failed".to_string(),
644 detail: "Failed to connect to HS".to_string(),
645 status: 400,
646 identifier: req.identifier,
647 instance: None,
648 sub_problems: vec![],
649 }]
650 }),
651 }))
652 };
653
654 Box::pin(hs_circ.relay_begin(&connection_string, None).await?)
655 } else {
656 match tokio::net::TcpStream::connect(connection_string.clone()).await {
657 Ok(s) => Box::pin(s),
658 Err(_) => return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
659 valid: false,
660 error: Some(crate::cert_order::ErrorResponse {
661 errors: vec![crate::cert_order::Error {
662 error_type: crate::cert_order::ErrorType::ConnectionError.into(),
663 title: "Connection failed".to_string(),
664 detail: format!("Failed to open TCP connection to {}", connection_string),
665 status: 400,
666 identifier: req.identifier,
667 instance: None,
668 sub_problems: vec![],
669 }]
670 }),
671 }))
672 }
673 };
674
675 let mut ssl_session = match openssl::ssl::Ssl::new(&ssl_ctx) {
676 Ok(b) => b,
677 Err(err) => {
678 error!("Failed to create SSL session: {}", err);
679 return Err(tonic::Status::internal("failed to create SSL session"));
680 }
681 };
682 ssl_session.set_hostname(&sni_string).unwrap();
683 let mut ssl_stream = match tokio_openssl::SslStream::new(ssl_session, tcp_stream) {
684 Ok(b) => b,
685 Err(err) => {
686 error!("Failed to create SSL stream: {}", err);
687 return Err(tonic::Status::internal("failed to create SSL stream"));
688 }
689 };
690
691 match std::pin::Pin::new(&mut ssl_stream).connect().await {
692 Ok(_) => {}
693 Err(_) => return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
694 valid: false,
695 error: Some(crate::cert_order::ErrorResponse {
696 errors: vec![crate::cert_order::Error {
697 error_type: crate::cert_order::ErrorType::TlsError.into(),
698 title: "Connection failed".to_string(),
699 detail: format!("Failed to negotiate TLS connection with {}", connection_string),
700 status: 400,
701 identifier: req.identifier,
702 instance: None,
703 sub_problems: vec![],
704 }]
705 }),
706 }))
707 }
708
709 let ssl_session_ref = ssl_stream.ssl();
710 let acme_identifier_oid = openssl::asn1::Asn1Object::from_str("1.3.6.1.5.5.7.1.31").unwrap();
711 let selected_alpn_protocol = ssl_session_ref.selected_alpn_protocol();
712 let peer_certificate = match ssl_session_ref.peer_certificate() {
713 Some(c) => c,
714 None => return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
715 valid: false,
716 error: Some(crate::cert_order::ErrorResponse {
717 errors: vec![crate::cert_order::Error {
718 error_type: crate::cert_order::ErrorType::TlsError.into(),
719 title: "No certificate".to_string(),
720 detail: "Server did not return a self signed certificate".to_string(),
721 status: 400,
722 identifier: req.identifier,
723 instance: None,
724 sub_problems: vec![],
725 }]
726 }),
727 }))
728 };
729
730 if selected_alpn_protocol != Some(b"acme-tls/1") {
731 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
732 valid: false,
733 error: Some(crate::cert_order::ErrorResponse {
734 errors: vec![crate::cert_order::Error {
735 error_type: crate::cert_order::ErrorType::TlsError.into(),
736 title: "ALPN failed".to_string(),
737 detail: "Server did not negotiate \"acme-tls/1\" protocol".to_string(),
738 status: 400,
739 identifier: req.identifier,
740 instance: None,
741 sub_problems: vec![],
742 }]
743 }),
744 }));
745 }
746
747 let mut subject_alt_names = match peer_certificate.subject_alt_names() {
748 Some(n) => n,
749 None => return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
750 valid: false,
751 error: Some(crate::cert_order::ErrorResponse {
752 errors: vec![crate::cert_order::Error {
753 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
754 title: "No SANs".to_string(),
755 detail: "Server did not return a SAN in its self signed certificate".to_string(),
756 status: 400,
757 identifier: req.identifier,
758 instance: None,
759 sub_problems: vec![],
760 }]
761 }),
762 }))
763 };
764
765 if subject_alt_names.len() != 1 {
766 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
767 valid: false,
768 error: Some(crate::cert_order::ErrorResponse {
769 errors: vec![crate::cert_order::Error {
770 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
771 title: "Invalid SANs".to_string(),
772 detail: "Server did not return only one SAN in its self signed certificate".to_string(),
773 status: 400,
774 identifier: req.identifier,
775 instance: None,
776 sub_problems: vec![],
777 }]
778 }),
779 }));
780 }
781 let subject_alt_name = subject_alt_names.pop().unwrap();
782 if ip_bytes.is_empty() {
783 if let Some(domain_alt_name) = subject_alt_name.dnsname() {
784 if domain_alt_name.to_ascii_lowercase() != sni_string {
785 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
786 valid: false,
787 error: Some(crate::cert_order::ErrorResponse {
788 errors: vec![crate::cert_order::Error {
789 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
790 title: "Invalid SANs".to_string(),
791 detail: format!("Server returned a SAN for '{}' its self signed certificate, expected '{}'", domain_alt_name, sni_string),
792 status: 400,
793 identifier: req.identifier,
794 instance: None,
795 sub_problems: vec![],
796 }]
797 }),
798 }));
799 }
800 } else {
801 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
802 valid: false,
803 error: Some(crate::cert_order::ErrorResponse {
804 errors: vec![crate::cert_order::Error {
805 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
806 title: "Invalid SANs".to_string(),
807 detail: "Server did not return a domain SAN in its self signed certificate".to_string(),
808 status: 400,
809 identifier: req.identifier,
810 instance: None,
811 sub_problems: vec![],
812 }]
813 }),
814 }));
815 }
816 } else {
817 if let Some(ip_alt_name) = subject_alt_name.ipaddress() {
818 if ip_alt_name != ip_bytes {
819 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
820 valid: false,
821 error: Some(crate::cert_order::ErrorResponse {
822 errors: vec![crate::cert_order::Error {
823 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
824 title: "Invalid SANs".to_string(),
825 detail: format!("Server returned a SAN for '{:X?}' its self signed certificate, expected '{:X?}'", ip_alt_name, ip_bytes),
826 status: 400,
827 identifier: req.identifier,
828 instance: None,
829 sub_problems: vec![],
830 }]
831 }),
832 }));
833 }
834 } else {
835 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
836 valid: false,
837 error: Some(crate::cert_order::ErrorResponse {
838 errors: vec![crate::cert_order::Error {
839 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
840 title: "Invalid SANs".to_string(),
841 detail: "Server did not return an IP SAN in its self signed certificate".to_string(),
842 status: 400,
843 identifier: req.identifier,
844 instance: None,
845 sub_problems: vec![],
846 }]
847 }),
848 }));
849 }
850 }
851
852 let acme_id_data_bytes = unsafe {
853 let extensions = openssl_sys::X509_get0_extensions(peer_certificate.as_ptr());
854 let acme_id_idx = X509v3_get_ext_by_OBJ(extensions, acme_identifier_oid.as_ptr(), -1);
855 if acme_id_idx < 0 {
856 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
857 valid: false,
858 error: Some(crate::cert_order::ErrorResponse {
859 errors: vec![crate::cert_order::Error {
860 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
861 title: "No acmeIdentifier extensions".to_string(),
862 detail: "Server did not return a acmeIdentifier with the key authorization in its self signed certificate".to_string(),
863 status: 400,
864 identifier: req.identifier,
865 instance: None,
866 sub_problems: vec![],
867 }]
868 }),
869 }));
870 }
871
872 let acme_id_ext = openssl_sys::X509v3_get_ext(extensions, acme_id_idx);
873
874 if openssl_sys::X509_EXTENSION_get_critical(acme_id_ext) != 1 {
875 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
876 valid: false,
877 error: Some(crate::cert_order::ErrorResponse {
878 errors: vec![crate::cert_order::Error {
879 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
880 title: "Invalid acmeIdentifier extension".to_string(),
881 detail: "Server returned a non critical acmeIdentifier extension in its self signed certificate".to_string(),
882 status: 400,
883 identifier: req.identifier,
884 instance: None,
885 sub_problems: vec![],
886 }]
887 }),
888 }));
889 }
890
891 let acme_id_ext_data = openssl_sys::X509_EXTENSION_get_data(acme_id_ext);
892 let acme_id_data = match crate::util::cvt_p(d2i_ASN1_OCTET_STRING(
893 std::ptr::null_mut(),
894 &mut openssl_sys::ASN1_STRING_get0_data(acme_id_ext_data as *const openssl_sys::ASN1_STRING),
895 openssl_sys::ASN1_STRING_length(acme_id_ext_data as *const openssl_sys::ASN1_STRING) as libc::c_long,
896 )) {
897 Ok(d) => d,
898 Err(_) => {
899 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
900 valid: false,
901 error: Some(crate::cert_order::ErrorResponse {
902 errors: vec![crate::cert_order::Error {
903 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
904 title: "Invalid acmeIdentifier extension".to_string(),
905 detail: "Server returned an un-parsable acmeIdentifier extension in its self signed certificate".to_string(),
906 status: 400,
907 identifier: req.identifier,
908 instance: None,
909 sub_problems: vec![],
910 }]
911 }),
912 }));
913 }
914 };
915 std::slice::from_raw_parts(
916 openssl_sys::ASN1_STRING_get0_data(acme_id_data as *const openssl_sys::ASN1_STRING),
917 openssl_sys::ASN1_STRING_length(acme_id_data as *const openssl_sys::ASN1_STRING) as usize,
918 )
919 };
920
921 Ok(tonic::Response::new(if acme_id_data_bytes == key_auth_hash_bytes {
922 crate::cert_order::ValidationResult {
923 valid: true,
924 error: None,
925 }
926 } else {
927 crate::cert_order::ValidationResult {
928 valid: false,
929 error: Some(crate::cert_order::ErrorResponse {
930 errors: vec![crate::cert_order::Error {
931 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
932 title: "Invalid acmeIdentifier extension".to_string(),
933 detail: format!("Server returned '{:X?}', expected '{:X?}'", acme_id_data_bytes, key_auth_hash_bytes),
934 status: 400,
935 identifier: req.identifier,
936 instance: None,
937 sub_problems: vec![],
938 }]
939 }),
940 }
941 }))
942 }
943
944 async fn validate_onion_csr01(
945 &self, request: tonic::Request<crate::cert_order::OnionCsrValidationRequest>,
946 ) -> Result<tonic::Response<crate::cert_order::ValidationResult>, tonic::Status> {
947 let req = request.into_inner();
948 let identifier = map_identifier(req.identifier.clone())?;
949
950 let hs_addr = match identifier {
951 Identifier::Domain(domain, _) => {
952 if !domain.ends_with(".onion") {
953 return Err(tonic::Status::invalid_argument("onion-csr-01 must not be used for non .onion domains"))
954 }
955 match torrosion::hs::HSAddress::from_str(&domain) {
956 Ok(addr) => addr,
957 Err(_) => {
958 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
959 valid: false,
960 error: Some(crate::cert_order::ErrorResponse {
961 errors: vec![crate::cert_order::Error {
962 error_type: crate::cert_order::ErrorType::UnsupportedIdentifierError.into(),
963 title: "Invalid domain".to_string(),
964 detail: "Malformed HS address".to_string(),
965 status: 400,
966 identifier: req.identifier,
967 instance: None,
968 sub_problems: vec![],
969 }]
970 }),
971 }))
972 }
973 }
974 },
975 Identifier::IPAddr(_) => return Err(tonic::Status::invalid_argument("onion-csr-01 must not be used for IP addresses")),
976 Identifier::Email(_) => return Err(tonic::Status::invalid_argument("onion-csr-01 makes no sense for email")),
977 };
978
979 let addr_pub_key = openssl::pkey::PKey::public_key_from_raw_bytes(
980 &hs_addr.key, openssl::pkey::Id::ED25519
981 ).unwrap();
982
983 let csr = match openssl::x509::X509Req::from_der(&req.csr) {
984 Ok(csr) => csr,
985 Err(_) => {
986 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
987 valid: false,
988 error: Some(crate::cert_order::ErrorResponse {
989 errors: vec![crate::cert_order::Error {
990 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
991 title: "Invalid CSR".to_string(),
992 detail: "CSR could not be parsed".to_string(),
993 status: 400,
994 identifier: req.identifier,
995 instance: None,
996 sub_problems: vec![],
997 }]
998 }),
999 }));
1000 }
1001 };
1002
1003 let req_pub_key = match csr.public_key() {
1004 Ok(k) => k,
1005 Err(_) => {
1006 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
1007 valid: false,
1008 error: Some(crate::cert_order::ErrorResponse {
1009 errors: vec![crate::cert_order::Error {
1010 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
1011 title: "Invalid CSR".to_string(),
1012 detail: "CSR could not be parsed".to_string(),
1013 status: 400,
1014 identifier: req.identifier,
1015 instance: None,
1016 sub_problems: vec![],
1017 }]
1018 }),
1019 }));
1020 }
1021 };
1022
1023 if !req_pub_key.public_eq(&addr_pub_key) {
1024 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
1025 valid: false,
1026 error: Some(crate::cert_order::ErrorResponse {
1027 errors: vec![crate::cert_order::Error {
1028 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
1029 title: "Invalid CSR".to_string(),
1030 detail: "CSR public key does not match public key of .onion domain".to_string(),
1031 status: 400,
1032 identifier: req.identifier,
1033 instance: None,
1034 sub_problems: vec![],
1035 }]
1036 }),
1037 }));
1038 }
1039
1040 if !csr.verify(&addr_pub_key).map_or(false, |r| r) {
1041 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
1042 valid: false,
1043 error: Some(crate::cert_order::ErrorResponse {
1044 errors: vec![crate::cert_order::Error {
1045 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
1046 title: "Invalid CSR".to_string(),
1047 detail: "CSR signature invalid".to_string(),
1048 status: 400,
1049 identifier: req.identifier,
1050 instance: None,
1051 sub_problems: vec![],
1052 }]
1053 }),
1054 }));
1055 }
1056
1057 let ca_nonce_oid = openssl::asn1::Asn1Object::from_str("2.23.140.41").unwrap();
1058 let applicant_nonce_oid = openssl::asn1::Asn1Object::from_str("2.23.140.42").unwrap();
1059
1060 let ca_nonce_at_i = unsafe {
1061 X509_REQ_get_attr_by_OBJ(csr.as_ptr(), ca_nonce_oid.as_ptr(), -1)
1062 };
1063 let applicant_nonce_at_i = unsafe {
1064 X509_REQ_get_attr_by_OBJ(csr.as_ptr(), applicant_nonce_oid.as_ptr(), -1)
1065 };
1066
1067 if ca_nonce_at_i < 0 {
1068 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
1069 valid: false,
1070 error: Some(crate::cert_order::ErrorResponse {
1071 errors: vec![crate::cert_order::Error {
1072 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
1073 title: "Invalid CSR".to_string(),
1074 detail: "CA nonce attribute not present".to_string(),
1075 status: 400,
1076 identifier: req.identifier,
1077 instance: None,
1078 sub_problems: vec![],
1079 }]
1080 }),
1081 }));
1082 }
1083
1084 if applicant_nonce_at_i < 0 {
1085 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
1086 valid: false,
1087 error: Some(crate::cert_order::ErrorResponse {
1088 errors: vec![crate::cert_order::Error {
1089 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
1090 title: "Invalid CSR".to_string(),
1091 detail: "Applicanct nonce attribute not present".to_string(),
1092 status: 400,
1093 identifier: req.identifier,
1094 instance: None,
1095 sub_problems: vec![],
1096 }]
1097 }),
1098 }));
1099 }
1100
1101 let ca_nonce_at_i2 = unsafe {
1102 X509_REQ_get_attr_by_OBJ(csr.as_ptr(), ca_nonce_oid.as_ptr(), ca_nonce_at_i)
1103 };
1104 let applicant_nonce_at_i2 = unsafe {
1105 X509_REQ_get_attr_by_OBJ(csr.as_ptr(), applicant_nonce_oid.as_ptr(), applicant_nonce_at_i)
1106 };
1107
1108 if ca_nonce_at_i2 >= 0 {
1109 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
1110 valid: false,
1111 error: Some(crate::cert_order::ErrorResponse {
1112 errors: vec![crate::cert_order::Error {
1113 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
1114 title: "Invalid CSR".to_string(),
1115 detail: "Multiple CA nonce attributes present".to_string(),
1116 status: 400,
1117 identifier: req.identifier,
1118 instance: None,
1119 sub_problems: vec![],
1120 }]
1121 }),
1122 }));
1123 }
1124
1125 if applicant_nonce_at_i2 >= 0 {
1126 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
1127 valid: false,
1128 error: Some(crate::cert_order::ErrorResponse {
1129 errors: vec![crate::cert_order::Error {
1130 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
1131 title: "Invalid CSR".to_string(),
1132 detail: "Multiple applicant nonce attributes present".to_string(),
1133 status: 400,
1134 identifier: req.identifier,
1135 instance: None,
1136 sub_problems: vec![],
1137 }]
1138 }),
1139 }));
1140 }
1141
1142 let ca_nonce_attr = unsafe {
1143 X509_REQ_get_attr(csr.as_ptr(), ca_nonce_at_i)
1144 };
1145 let applicant_nonce_attr = unsafe {
1146 X509_REQ_get_attr(csr.as_ptr(), applicant_nonce_at_i)
1147 };
1148
1149 let ca_nonce_attr_count = unsafe {
1150 X509_ATTRIBUTE_count(ca_nonce_attr)
1151 };
1152 let applicant_nonce_attr_count = unsafe {
1153 X509_ATTRIBUTE_count(applicant_nonce_attr)
1154 };
1155
1156 if ca_nonce_attr_count != 1 {
1157 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
1158 valid: false,
1159 error: Some(crate::cert_order::ErrorResponse {
1160 errors: vec![crate::cert_order::Error {
1161 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
1162 title: "Invalid CSR".to_string(),
1163 detail: "CA nonce attribute doesn't contain only one value".to_string(),
1164 status: 400,
1165 identifier: req.identifier,
1166 instance: None,
1167 sub_problems: vec![],
1168 }]
1169 }),
1170 }));
1171 }
1172
1173 if applicant_nonce_attr_count != 1 {
1174 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
1175 valid: false,
1176 error: Some(crate::cert_order::ErrorResponse {
1177 errors: vec![crate::cert_order::Error {
1178 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
1179 title: "Invalid CSR".to_string(),
1180 detail: "Applicant nonce attribute doesn't contain only one value".to_string(),
1181 status: 400,
1182 identifier: req.identifier,
1183 instance: None,
1184 sub_problems: vec![],
1185 }]
1186 }),
1187 }));
1188 }
1189
1190 let ca_nonce_attr_value = match unsafe {
1191 crate::util::cvt_p(X509_ATTRIBUTE_get0_data(
1192 ca_nonce_attr, 0, openssl_sys::V_ASN1_OCTET_STRING, std::ptr::null()
1193 ))
1194 } {
1195 Ok(v) => unsafe {
1196 openssl::asn1::Asn1StringRef::from_ptr(v as *mut openssl_sys::ASN1_STRING)
1197 },
1198 Err(_) => {
1199 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
1200 valid: false,
1201 error: Some(crate::cert_order::ErrorResponse {
1202 errors: vec![crate::cert_order::Error {
1203 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
1204 title: "Invalid CSR".to_string(),
1205 detail: "Invalid data type for CA nonce attribute".to_string(),
1206 status: 400,
1207 identifier: req.identifier,
1208 instance: None,
1209 sub_problems: vec![],
1210 }]
1211 }),
1212 }));
1213 }
1214 };
1215
1216 let applicant_nonce_attr_value = match unsafe {
1217 crate::util::cvt_p(X509_ATTRIBUTE_get0_data(
1218 applicant_nonce_attr, 0, openssl_sys::V_ASN1_OCTET_STRING, std::ptr::null()
1219 ))
1220 } {
1221 Ok(v) => unsafe {
1222 openssl::asn1::Asn1StringRef::from_ptr(v as *mut openssl_sys::ASN1_STRING)
1223 },
1224 Err(_) => {
1225 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
1226 valid: false,
1227 error: Some(crate::cert_order::ErrorResponse {
1228 errors: vec![crate::cert_order::Error {
1229 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
1230 title: "Invalid CSR".to_string(),
1231 detail: "Invalid data type for applicant nonce attribute".to_string(),
1232 status: 400,
1233 identifier: req.identifier,
1234 instance: None,
1235 sub_problems: vec![],
1236 }]
1237 }),
1238 }));
1239 }
1240 };
1241
1242 if applicant_nonce_attr_value.len() < 8 {
1243 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
1244 valid: false,
1245 error: Some(crate::cert_order::ErrorResponse {
1246 errors: vec![crate::cert_order::Error {
1247 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
1248 title: "Invalid CSR".to_string(),
1249 detail: "Applicant nonce attribute does not contain at least 64 bits of entropy".to_string(),
1250 status: 400,
1251 identifier: req.identifier,
1252 instance: None,
1253 sub_problems: vec![],
1254 }]
1255 }),
1256 }));
1257 }
1258
1259 if ca_nonce_attr_value.as_slice() != req.ca_nonce {
1260 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
1261 valid: false,
1262 error: Some(crate::cert_order::ErrorResponse {
1263 errors: vec![crate::cert_order::Error {
1264 error_type: crate::cert_order::ErrorType::IncorrectResponseError.into(),
1265 title: "Invalid CSR".to_string(),
1266 detail: "CA nonce attribute does not CA provided value".to_string(),
1267 status: 400,
1268 identifier: req.identifier,
1269 instance: None,
1270 sub_problems: vec![],
1271 }]
1272 }),
1273 }));
1274 } else {
1275 return Ok(tonic::Response::new(crate::cert_order::ValidationResult {
1276 valid: true,
1277 error: None
1278 }));
1279 }
1280 }
1281}
1282
1283#[allow(non_camel_case_types)]
1284enum X509_ATTRIBUTE {}
1285
1286extern "C" {
1287 fn X509v3_get_ext_by_OBJ(
1288 x: *const openssl_sys::stack_st_X509_EXTENSION,
1289 obj: *const openssl_sys::ASN1_OBJECT,
1290 lastpos: libc::c_int,
1291 ) -> libc::c_int;
1292
1293 fn d2i_ASN1_OCTET_STRING(
1294 a: *mut *mut openssl_sys::ASN1_OCTET_STRING,
1295 pp: *mut *const libc::c_uchar,
1296 length: libc::c_long,
1297 ) -> *mut openssl_sys::ASN1_OCTET_STRING;
1298
1299 fn X509_REQ_get_attr_by_OBJ(
1300 req: *const openssl_sys::X509_REQ,
1301 obj: *const openssl_sys::ASN1_OBJECT,
1302 start_after: libc::c_int,
1303 ) -> libc::c_int;
1304
1305
1306 fn X509_REQ_get_attr(
1307 req: *const openssl_sys::X509_REQ, index: libc::c_int
1308 ) -> *const X509_ATTRIBUTE;
1309
1310 fn X509_ATTRIBUTE_count(attr: *const X509_ATTRIBUTE) -> libc::c_int;
1311
1312 fn X509_ATTRIBUTE_get0_data(
1313 attr: *const X509_ATTRIBUTE,
1314 index: libc::c_int,
1315 data_type: libc::c_int,
1316 data: *const libc::c_void
1317 ) -> *mut libc::c_void;
1318}