@@ -11,25 +11,26 @@ use std::string::{String, ToString};
1111
1212use bytes:: Bytes ;
1313use error:: { NewAccountError , NewCertificateError , RequestError } ;
14- use http:: Uri ;
14+ use http:: { Response , Uri } ;
1515use ngx:: allocator:: { Allocator , Box } ;
1616use ngx:: async_:: sleep;
1717use ngx:: collections:: Vec ;
1818use ngx:: ngx_log_debug;
1919use openssl:: pkey:: { PKey , PKeyRef , Private } ;
20- use openssl:: x509:: { self , extension as x509_ext, X509Req } ;
20+ use openssl:: x509:: { self , extension as x509_ext, X509Req , X509 } ;
2121use types:: { AccountStatus , ProblemCategory } ;
2222
2323use self :: account_key:: { AccountKey , AccountKeyError } ;
2424use self :: types:: { AuthorizationStatus , ChallengeKind , ChallengeStatus , OrderStatus } ;
2525use crate :: conf:: identifier:: Identifier ;
26- use crate :: conf:: issuer:: { Issuer , Profile } ;
26+ use crate :: conf:: issuer:: { CertificateChainMatcher , Issuer , Profile } ;
2727use crate :: conf:: order:: CertificateOrder ;
2828use crate :: net:: http:: HttpClient ;
2929use crate :: time:: Time ;
3030
3131pub mod account_key;
3232pub mod error;
33+ pub mod headers;
3334pub mod solvers;
3435pub mod types;
3536
@@ -49,7 +50,8 @@ pub enum NewAccountOutput<'a> {
4950}
5051
5152pub struct NewCertificateOutput {
52- pub chain : Bytes ,
53+ pub bytes : Bytes ,
54+ pub x509 : std:: vec:: Vec < X509 > ,
5355 pub pkey : PKey < Private > ,
5456}
5557
@@ -246,7 +248,7 @@ where
246248 if let Some ( val) = res
247249 . headers ( )
248250 . get ( http:: header:: RETRY_AFTER )
249- . and_then ( parse_retry_after)
251+ . and_then ( headers :: parse_retry_after)
250252 . filter ( |x| x > & MAX_SERVER_RETRY_INTERVAL )
251253 {
252254 return Err ( RequestError :: RateLimited ( val) ) ;
@@ -461,11 +463,69 @@ where
461463
462464 let certificate = order
463465 . certificate
464- . ok_or ( NewCertificateError :: CertificateUrl ) ?;
466+ . ok_or ( NewCertificateError :: MissingCertificate ) ?;
465467
466- let chain = self . post ( & certificate, b"" ) . await ?. into_body ( ) ;
468+ let res = self . post ( & certificate, b"" ) . await ?;
467469
468- Ok ( NewCertificateOutput { chain, pkey } )
470+ if let Some ( ref matcher) = self . issuer . chain {
471+ let ( bytes, x509) = self
472+ . find_preferred_chain ( & certificate, res, matcher)
473+ . await ?;
474+ Ok ( NewCertificateOutput { bytes, x509, pkey } )
475+ } else {
476+ let bytes = res. into_body ( ) ;
477+ let x509 =
478+ X509 :: stack_from_pem ( & bytes) . map_err ( NewCertificateError :: InvalidCertificate ) ?;
479+ if x509. is_empty ( ) {
480+ return Err ( NewCertificateError :: MissingCertificate ) ;
481+ }
482+
483+ Ok ( NewCertificateOutput { bytes, x509, pkey } )
484+ }
485+ }
486+
487+ async fn find_preferred_chain (
488+ & self ,
489+ base : & Uri ,
490+ cert : Response < Bytes > ,
491+ matcher : & CertificateChainMatcher ,
492+ ) -> Result < ( Bytes , std:: vec:: Vec < X509 > ) , NewCertificateError > {
493+ let default =
494+ X509 :: stack_from_pem ( cert. body ( ) ) . map_err ( NewCertificateError :: InvalidCertificate ) ?;
495+
496+ if !matcher. test ( & default) {
497+ if let Ok ( base) = iri_string:: types:: UriAbsoluteString :: try_from ( base. to_string ( ) ) {
498+ let alternates = cert
499+ . headers ( )
500+ . get_all ( http:: header:: LINK )
501+ . into_iter ( )
502+ . filter_map ( headers:: parse_link)
503+ . flatten ( )
504+ . filter ( |x| x. is_rel ( "alternate" ) ) ;
505+
506+ for link in alternates {
507+ let uri = link. target . resolve_against ( & base) . to_string ( ) ;
508+ let Ok ( uri) = Uri :: try_from ( uri) else {
509+ continue ;
510+ } ;
511+
512+ let res = self . post ( & uri, b"" ) . await ?;
513+ let bytes = res. into_body ( ) ;
514+
515+ let stack = X509 :: stack_from_pem ( & bytes)
516+ . map_err ( NewCertificateError :: InvalidCertificate ) ?;
517+ if matcher. test ( & stack) {
518+ return Ok ( ( bytes, stack) ) ;
519+ }
520+ }
521+ }
522+ }
523+
524+ if default. is_empty ( ) {
525+ return Err ( NewCertificateError :: MissingCertificate ) ;
526+ }
527+
528+ Ok ( ( cert. into_body ( ) , default) )
469529 }
470530
471531 async fn do_authorization (
@@ -586,7 +646,7 @@ async fn wait_for_retry<B>(
586646 let retry_after = res
587647 . headers ( )
588648 . get ( http:: header:: RETRY_AFTER )
589- . and_then ( parse_retry_after)
649+ . and_then ( headers :: parse_retry_after)
590650 . unwrap_or ( interval)
591651 . min ( MAX_SERVER_RETRY_INTERVAL ) ;
592652
@@ -616,15 +676,3 @@ where
616676{
617677 serde_json:: from_slice ( bytes) . map_err ( RequestError :: ResponseFormat )
618678}
619-
620- fn parse_retry_after ( val : & http:: HeaderValue ) -> Option < Duration > {
621- let val = val. to_str ( ) . ok ( ) ?;
622-
623- // Retry-After: <http-date>
624- if let Ok ( time) = Time :: parse ( val) {
625- return Some ( time - Time :: now ( ) ) ;
626- }
627-
628- // Retry-After: <delay-seconds>
629- val. parse ( ) . map ( Duration :: from_secs) . ok ( )
630- }
0 commit comments