@@ -191,8 +191,7 @@ func (bh *BaseHandler) APIRequestCertificateWithCSRHandler(w http.ResponseWriter
191191 return
192192 }
193193
194- val := r .Context ().Value ("user" )
195- u := val .(entity.User )
194+ u := r .Context ().Value ("user" ).(entity.User )
196195
197196 ri := entity.RequestInfo {
198197 CreatedFor : u .ID ,
@@ -552,7 +551,7 @@ func (bh *BaseHandler) APISolveHTTP01ChallengeHandler(w http.ResponseWriter, r *
552551 ips = simpleRequest .IPs
553552 }
554553
555- // check well known path for every domain
554+ // check well- known path for every domain
556555 for _ , domain := range domains {
557556 if domain == "" {
558557 continue
@@ -662,10 +661,157 @@ func (bh *BaseHandler) APISolveHTTP01ChallengeHandler(w http.ResponseWriter, r *
662661
663662func (bh * BaseHandler ) APISolveDNS01ChallengeHandler (w http.ResponseWriter , r * http.Request ) {
664663 defer r .Body .Close ()
665- // var (
666- // logger = bh.ContextLogger("api")
667- // vars = mux.Vars(r)
668- // )
664+ var (
665+ logger = bh .ContextLogger ("api" )
666+ vars = mux .Vars (r )
667+ )
668+
669+ var response entity.CertificateResponse
670+
671+ // fetch challenge info from DB
672+ challenge , err := bh .DBSvc .FindChallenge ("public_id = ?" , vars ["challengeID" ])
673+ if err != nil {
674+ if err == sql .ErrNoRows {
675+ logger .Debugf ("no challenge found for public ID %s" , vars ["challengeID" ])
676+ w .WriteHeader (http .StatusNotFound )
677+ return
678+ }
679+ logger .Errorf ("could not query challenge: %s" , err .Error ())
680+ w .WriteHeader (http .StatusInternalServerError )
681+ return
682+ }
683+
684+ // check if challenge type matches
685+ if challenge .ChallengeType != "dns-01" {
686+ logger .Debugf ("challenge type is not dns-01: %s" , challenge .ChallengeType )
687+ w .WriteHeader (http .StatusBadRequest )
688+ return
689+ }
690+
691+ // get requestInfo for challenge
692+ requestInfo , err := bh .DBSvc .GetRequestInfo (challenge .RequestInfoID )
693+ if err != nil {
694+ logger .Errorf ("could not get request info for ID %v: %s" , challenge .RequestInfoID , err .Error ())
695+ w .WriteHeader (http .StatusInternalServerError )
696+ return
697+ }
698+
699+ var (
700+ domains []string
701+ fromCSR = requestInfo .CsrBytes != nil
702+ csr * x509.CertificateRequest
703+ simpleRequest entity.SimpleRequest
704+ )
705+
706+ if fromCSR {
707+ // determine DNS names and IPs from CSR
708+ csr , err = x509 .ParseCertificateRequest (requestInfo .CsrBytes )
709+ if err != nil {
710+ logger .Errorf ("could not parse CSR: %s" , err .Error ())
711+ w .WriteHeader (http .StatusBadRequest )
712+ return
713+ }
714+
715+ domains = append (domains , csr .DNSNames ... )
716+ } else {
717+ err = json .Unmarshal (requestInfo .SimpleRequestBytes , & simpleRequest )
718+ if err != nil {
719+ logger .Errorf ("could not unmarshal simple request: %s" , err .Error ())
720+ w .WriteHeader (http .StatusBadRequest )
721+ return
722+ }
723+
724+ domains = simpleRequest .Domains
725+ }
726+
727+ // check well known path for every domain
728+ for _ , domain := range domains {
729+ if domain == "" {
730+ continue
731+ }
732+
733+ if helper .StringSliceContains (global .DNSNamesToSkip , domain ) {
734+ continue
735+ }
736+
737+ ok , err := challenges .CheckDNS01Challenge (domain , challenge .Token )
738+ if err != nil {
739+ response .Error = fmt .Sprintf ("error checking domain %s: %s" , domain , err .Error ())
740+ w .WriteHeader (http .StatusBadRequest )
741+ _ = json .NewEncoder (w ).Encode (response )
742+ return
743+ }
744+
745+ if ! ok {
746+ response .Error = fmt .Sprintf ("DNS check of TXT record for %s%s did not match expected token" , global .DNS01ChallengeSubdomain , domain )
747+ w .WriteHeader (http .StatusBadRequest )
748+ _ = json .NewEncoder (w ).Encode (response )
749+ return
750+ }
751+ }
752+
753+ // from here on, we know that the challenge was successful for all domains
754+ // that means we can issue the certificate
755+
756+ var (
757+ certBytes , keyBytes []byte
758+ sn int64
759+ )
760+ if fromCSR {
761+ // issue certificate from CSR
762+ certBytes , sn , err = bh .CertMaker .GenerateCertificateByCSR (csr )
763+ if err != nil {
764+ logger .Errorf ("error generating certificate from CSR: %s\n " , err .Error ())
765+ w .WriteHeader (http .StatusInternalServerError )
766+ return
767+ }
768+ } else {
769+ certBytes , keyBytes , sn , err = bh .CertMaker .GenerateLeafCertAndKey (simpleRequest )
770+ if err != nil {
771+ logger .Errorf ("error generating key + certificate: %s\n " , err .Error ())
772+ w .WriteHeader (http .StatusInternalServerError )
773+ return
774+ }
775+ }
776+
777+ // update the request info status to "issued"
778+ requestInfo .Status = "issued"
779+ err = bh .DBSvc .UpdateRequestInfo (requestInfo )
780+ if err != nil {
781+ logger .Errorf ("could not update request info status: %s" , err .Error ())
782+ w .WriteHeader (http .StatusInternalServerError )
783+ return
784+ }
785+
786+ // store certificate info in DB
787+ ci := entity.CertInfo {
788+ SerialNumber : sn ,
789+ FromCSR : fromCSR ,
790+ CreatedForUser : challenge .CreatedFor ,
791+ Revoked : false ,
792+ }
793+
794+ err = bh .DBSvc .AddCertInfo (& ci )
795+ if err != nil {
796+ logger .Errorf ("could not insert cert info into DB: %s" , err .Error ())
797+ w .WriteHeader (http .StatusInternalServerError )
798+ return
799+ }
800+
801+ // set up response
802+ response .CertificatePem = string (certBytes )
803+ if ! fromCSR {
804+ response .PrivateKeyPem = string (keyBytes )
805+ }
806+
807+ w .Header ().Set ("Content-Type" , "application/json" )
808+ w .WriteHeader (http .StatusCreated )
809+ err = json .NewEncoder (w ).Encode (response )
810+ if err != nil {
811+ logger .Infof ("could not encode response: %s" , err .Error ())
812+ w .WriteHeader (http .StatusInternalServerError )
813+ return
814+ }
669815}
670816
671817// APIRootCertificateDownloadHandler allows to programmatically obtain the root certificate
@@ -692,6 +838,7 @@ func (bh *BaseHandler) APIRootCertificateDownloadHandler(w http.ResponseWriter,
692838 _ = fh .Close ()
693839}
694840
841+ // APIRevokeCertificateHandler allows a user to revoke a certificate by its serial number
695842func (bh * BaseHandler ) APIRevokeCertificateHandler (w http.ResponseWriter , r * http.Request ) {
696843 defer r .Body .Close ()
697844 var (
0 commit comments