// Copyright 2014 ISRG. All rights reserved // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. package rpc import ( "crypto/x509" "encoding/json" "errors" "fmt" "net" "time" "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/cactus/go-statsd-client/statsd" jose "github.com/letsencrypt/boulder/Godeps/_workspace/src/github.com/letsencrypt/go-jose" "github.com/letsencrypt/boulder/cmd" "github.com/letsencrypt/boulder/core" blog "github.com/letsencrypt/boulder/log" ) // This file defines RPC wrappers around the ${ROLE}Impl classes, // where ROLE covers: // * RegistrationAuthority // * ValidationAuthority // * CertificateAuthority // * StorageAuthority // // For each one of these, the are ${ROLE}Client and ${ROLE}Server // types. ${ROLE}Server is to be run on the server side, as a more // or less stand-alone component. ${ROLE}Client is loaded by the // code making use of the functionality. // // The WebFrontEnd role does not expose any functionality over RPC, // so it doesn't need wrappers. // These strings are used by the RPC layer to identify function points. const ( MethodNewRegistration = "NewRegistration" // RA, SA MethodNewAuthorization = "NewAuthorization" // RA MethodNewCertificate = "NewCertificate" // RA MethodUpdateRegistration = "UpdateRegistration" // RA, SA MethodUpdateAuthorization = "UpdateAuthorization" // RA MethodRevokeCertificate = "RevokeCertificate" // CA MethodRevokeCertificateWithReg = "RevokeCertificateWithReg" // RA MethodAdministrativelyRevokeCertificate = "AdministrativelyRevokeCertificate" // RA MethodOnValidationUpdate = "OnValidationUpdate" // RA MethodUpdateValidations = "UpdateValidations" // VA MethodCheckCAARecords = "CheckCAARecords" // VA MethodIsSafeDomain = "IsSafeDomain" // VA MethodIssueCertificate = "IssueCertificate" // CA MethodGenerateOCSP = "GenerateOCSP" // CA MethodGetRegistration = "GetRegistration" // SA MethodGetRegistrationByKey = "GetRegistrationByKey" // RA, SA MethodGetAuthorization = "GetAuthorization" // SA MethodGetLatestValidAuthorization = "GetLatestValidAuthorization" // SA MethodGetAuthorizationsByDomain = "GetAuthorizationsByDomain" // SA MethodGetCertificate = "GetCertificate" // SA MethodGetCertificateStatus = "GetCertificateStatus" // SA MethodMarkCertificateRevoked = "MarkCertificateRevoked" // SA MethodUpdateOCSP = "UpdateOCSP" // SA MethodNewPendingAuthorization = "NewPendingAuthorization" // SA MethodUpdatePendingAuthorization = "UpdatePendingAuthorization" // SA MethodFinalizeAuthorization = "FinalizeAuthorization" // SA MethodAddCertificate = "AddCertificate" // SA MethodAlreadyDeniedCSR = "AlreadyDeniedCSR" // SA MethodCountCertificatesRange = "CountCertificatesRange" // SA MethodCountCertificatesByNames = "CountCertificatesByNames" // SA MethodCountRegistrationsByIP = "CountRegistrationsByIP" // SA MethodCountPendingAuthorizations = "CountPendingAuthorizations" // SA MethodGetSCTReceipt = "GetSCTReceipt" // SA MethodAddSCTReceipt = "AddSCTReceipt" // SA MethodSubmitToCT = "SubmitToCT" // Pub MethodRevokeAuthorization = "RevokeAuthorization" // SA ) // Request structs type registrationRequest struct { Reg core.Registration } type getRegistrationRequest struct { ID int64 } type updateRegistrationRequest struct { Base, Update core.Registration } type authorizationRequest struct { Authz core.Authorization RegID int64 } type updateAuthorizationRequest struct { Authz core.Authorization Index int Response core.Challenge } type latestValidAuthorizationRequest struct { RegID int64 Identifier core.AcmeIdentifier } type certificateRequest struct { Req core.CertificateRequest RegID int64 } type issueCertificateRequest struct { Bytes []byte RegID int64 } type addCertificateRequest struct { Bytes []byte RegID int64 } type revokeCertificateRequest struct { Serial string ReasonCode core.RevocationCode } type markCertificateRevokedRequest struct { Serial string ReasonCode core.RevocationCode } type caaRequest struct { Ident core.AcmeIdentifier } type validationRequest struct { Authz core.Authorization Index int } type alreadyDeniedCSRReq struct { Names []string } type updateOCSPRequest struct { Serial string OCSPResponse []byte } type countRequest struct { Start time.Time End time.Time } type countCertificatesByNamesRequest struct { Names []string Earliest time.Time Latest time.Time } type countRegistrationsByIPRequest struct { IP net.IP Earliest time.Time Latest time.Time } type countPendingAuthorizationsRequest struct { RegID int64 } // Response structs type caaResponse struct { Present bool Valid bool Err error } func improperMessage(method string, err error, obj interface{}) { log := blog.GetAuditLogger() log.Audit(fmt.Sprintf("Improper message. method: %s err: %s data: %+v", method, err, obj)) } func errorCondition(method string, err error, obj interface{}) { log := blog.GetAuditLogger() log.Audit(fmt.Sprintf("Error condition. method: %s err: %s data: %+v", method, err, obj)) } // NewRegistrationAuthorityServer constructs an RPC server func NewRegistrationAuthorityServer(rpc Server, impl core.RegistrationAuthority) error { log := blog.GetAuditLogger() rpc.Handle(MethodNewRegistration, func(req []byte) (response []byte, err error) { var rr registrationRequest if err = json.Unmarshal(req, &rr); err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodNewRegistration, err, req) return } reg, err := impl.NewRegistration(rr.Reg) if err != nil { return } response, err = json.Marshal(reg) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodNewRegistration, err, req) return } return }) rpc.Handle(MethodNewAuthorization, func(req []byte) (response []byte, err error) { var ar authorizationRequest if err = json.Unmarshal(req, &ar); err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodNewAuthorization, err, req) return } authz, err := impl.NewAuthorization(ar.Authz, ar.RegID) if err != nil { return } response, err = json.Marshal(authz) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodNewAuthorization, err, req) return } return }) rpc.Handle(MethodNewCertificate, func(req []byte) (response []byte, err error) { log.Info(fmt.Sprintf(" [.] Entering MethodNewCertificate")) var cr certificateRequest if err = json.Unmarshal(req, &cr); err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodNewCertificate, err, req) return } log.Info(fmt.Sprintf(" [.] No problem unmarshaling request")) cert, err := impl.NewCertificate(cr.Req, cr.RegID) if err != nil { return } log.Info(fmt.Sprintf(" [.] No problem issuing new cert")) response, err = json.Marshal(cert) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodNewCertificate, err, req) return } return }) rpc.Handle(MethodUpdateRegistration, func(req []byte) (response []byte, err error) { var urReq updateRegistrationRequest err = json.Unmarshal(req, &urReq) if err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodUpdateRegistration, err, req) return } reg, err := impl.UpdateRegistration(urReq.Base, urReq.Update) if err != nil { return } response, err = json.Marshal(reg) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodUpdateRegistration, err, req) return } return }) rpc.Handle(MethodUpdateAuthorization, func(req []byte) (response []byte, err error) { var uaReq updateAuthorizationRequest err = json.Unmarshal(req, &uaReq) if err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodUpdateAuthorization, err, req) return } newAuthz, err := impl.UpdateAuthorization(uaReq.Authz, uaReq.Index, uaReq.Response) if err != nil { return } response, err = json.Marshal(newAuthz) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodUpdateAuthorization, err, req) return } return }) rpc.Handle(MethodRevokeCertificateWithReg, func(req []byte) (response []byte, err error) { var revReq struct { Cert []byte Reason core.RevocationCode RegID int64 } if err = json.Unmarshal(req, &revReq); err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodRevokeCertificateWithReg, err, req) return } cert, err := x509.ParseCertificate(revReq.Cert) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 return } err = impl.RevokeCertificateWithReg(*cert, revReq.Reason, revReq.RegID) return }) rpc.Handle(MethodAdministrativelyRevokeCertificate, func(req []byte) (response []byte, err error) { var revReq struct { Cert []byte Reason core.RevocationCode User string } if err = json.Unmarshal(req, &revReq); err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodAdministrativelyRevokeCertificate, err, req) return } cert, err := x509.ParseCertificate(revReq.Cert) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 return } err = impl.AdministrativelyRevokeCertificate(*cert, revReq.Reason, revReq.User) return }) rpc.Handle(MethodOnValidationUpdate, func(req []byte) (response []byte, err error) { var authz core.Authorization if err = json.Unmarshal(req, &authz); err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodOnValidationUpdate, err, req) return } err = impl.OnValidationUpdate(authz) return }) return nil } // RegistrationAuthorityClient represents an RA RPC client type RegistrationAuthorityClient struct { rpc Client } // NewRegistrationAuthorityClient constructs an RPC client func NewRegistrationAuthorityClient(clientName string, amqpConf *cmd.AMQPConfig, stats statsd.Statter) (*RegistrationAuthorityClient, error) { client, err := NewAmqpRPCClient(clientName+"->RA", amqpConf, amqpConf.RA, stats) return &RegistrationAuthorityClient{rpc: client}, err } // NewRegistration sends a New Registration request func (rac RegistrationAuthorityClient) NewRegistration(reg core.Registration) (newReg core.Registration, err error) { data, err := json.Marshal(registrationRequest{reg}) if err != nil { return } newRegData, err := rac.rpc.DispatchSync(MethodNewRegistration, data) if err != nil { return } err = json.Unmarshal(newRegData, &newReg) return } // NewAuthorization sends a New Authorization request func (rac RegistrationAuthorityClient) NewAuthorization(authz core.Authorization, regID int64) (newAuthz core.Authorization, err error) { data, err := json.Marshal(authorizationRequest{authz, regID}) if err != nil { return } newAuthzData, err := rac.rpc.DispatchSync(MethodNewAuthorization, data) if err != nil { return } err = json.Unmarshal(newAuthzData, &newAuthz) return } // NewCertificate sends a New Certificate request func (rac RegistrationAuthorityClient) NewCertificate(cr core.CertificateRequest, regID int64) (cert core.Certificate, err error) { data, err := json.Marshal(certificateRequest{cr, regID}) if err != nil { return } certData, err := rac.rpc.DispatchSync(MethodNewCertificate, data) if err != nil { return } err = json.Unmarshal(certData, &cert) return } // UpdateRegistration sends an Update Registration request func (rac RegistrationAuthorityClient) UpdateRegistration(base core.Registration, update core.Registration) (newReg core.Registration, err error) { var urReq updateRegistrationRequest urReq.Base = base urReq.Update = update data, err := json.Marshal(urReq) if err != nil { return } newRegData, err := rac.rpc.DispatchSync(MethodUpdateRegistration, data) if err != nil { return } err = json.Unmarshal(newRegData, &newReg) return } // UpdateAuthorization sends an Update Authorization request func (rac RegistrationAuthorityClient) UpdateAuthorization(authz core.Authorization, index int, response core.Challenge) (newAuthz core.Authorization, err error) { var uaReq updateAuthorizationRequest uaReq.Authz = authz uaReq.Index = index uaReq.Response = response data, err := json.Marshal(uaReq) if err != nil { return } newAuthzData, err := rac.rpc.DispatchSync(MethodUpdateAuthorization, data) if err != nil { return } err = json.Unmarshal(newAuthzData, &newAuthz) return } // RevokeCertificateWithReg sends a Revoke Certificate request initiated by the // WFE func (rac RegistrationAuthorityClient) RevokeCertificateWithReg(cert x509.Certificate, reason core.RevocationCode, regID int64) (err error) { var revReq struct { Cert []byte Reason core.RevocationCode RegID int64 } revReq.Cert = cert.Raw revReq.Reason = reason revReq.RegID = regID data, err := json.Marshal(revReq) if err != nil { return } _, err = rac.rpc.DispatchSync(MethodRevokeCertificateWithReg, data) return } // AdministrativelyRevokeCertificate sends a Revoke Certificate request initiated by the // admin-revoker func (rac RegistrationAuthorityClient) AdministrativelyRevokeCertificate(cert x509.Certificate, reason core.RevocationCode, user string) (err error) { var revReq struct { Cert []byte Reason core.RevocationCode User string } revReq.Cert = cert.Raw revReq.Reason = reason revReq.User = user data, err := json.Marshal(revReq) if err != nil { return } _, err = rac.rpc.DispatchSync(MethodAdministrativelyRevokeCertificate, data) return } // OnValidationUpdate senda a notice that a validation has updated func (rac RegistrationAuthorityClient) OnValidationUpdate(authz core.Authorization) (err error) { data, err := json.Marshal(authz) if err != nil { return } _, err = rac.rpc.DispatchSync(MethodOnValidationUpdate, data) return } // NewValidationAuthorityServer constructs an RPC server // // ValidationAuthorityClient / Server // -> UpdateValidations func NewValidationAuthorityServer(rpc Server, impl core.ValidationAuthority) (err error) { rpc.Handle(MethodUpdateValidations, func(req []byte) (response []byte, err error) { var vaReq validationRequest if err = json.Unmarshal(req, &vaReq); err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodUpdateValidations, err, req) return } err = impl.UpdateValidations(vaReq.Authz, vaReq.Index) return }) rpc.Handle(MethodCheckCAARecords, func(req []byte) (response []byte, err error) { var caaReq caaRequest if err = json.Unmarshal(req, &caaReq); err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodCheckCAARecords, err, req) return } present, valid, err := impl.CheckCAARecords(caaReq.Ident) if err != nil { return } var caaResp caaResponse caaResp.Present = present caaResp.Valid = valid caaResp.Err = err response, err = json.Marshal(caaResp) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodCheckCAARecords, err, caaReq) return } return }) rpc.Handle(MethodIsSafeDomain, func(req []byte) ([]byte, error) { r := &core.IsSafeDomainRequest{} if err := json.Unmarshal(req, r); err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodIsSafeDomain, err, req) return nil, err } resp, err := impl.IsSafeDomain(r) if err != nil { return nil, err } jsonResp, err := json.Marshal(resp) if err != nil { return nil, err } return jsonResp, nil }) return nil } // ValidationAuthorityClient represents an RPC client for the VA type ValidationAuthorityClient struct { rpc Client } // NewValidationAuthorityClient constructs an RPC client func NewValidationAuthorityClient(clientName string, amqpConf *cmd.AMQPConfig, stats statsd.Statter) (*ValidationAuthorityClient, error) { client, err := NewAmqpRPCClient(clientName+"->VA", amqpConf, amqpConf.VA, stats) return &ValidationAuthorityClient{rpc: client}, err } // UpdateValidations sends an Update Validations request func (vac ValidationAuthorityClient) UpdateValidations(authz core.Authorization, index int) error { vaReq := validationRequest{ Authz: authz, Index: index, } data, err := json.Marshal(vaReq) if err != nil { return err } _, err = vac.rpc.DispatchSync(MethodUpdateValidations, data) return nil } // CheckCAARecords sends a request to check CAA records func (vac ValidationAuthorityClient) CheckCAARecords(ident core.AcmeIdentifier) (present bool, valid bool, err error) { var caaReq caaRequest caaReq.Ident = ident data, err := json.Marshal(caaReq) if err != nil { return } jsonResp, err := vac.rpc.DispatchSync(MethodCheckCAARecords, data) if err != nil { return } var caaResp caaResponse err = json.Unmarshal(jsonResp, &caaResp) if err != nil { return } present = caaResp.Present valid = caaResp.Valid return } // IsSafeDomain returns true if the domain given is determined to be safe by an // third-party safe browsing API. func (vac ValidationAuthorityClient) IsSafeDomain(req *core.IsSafeDomainRequest) (*core.IsSafeDomainResponse, error) { data, err := json.Marshal(req) if err != nil { return nil, err } jsonResp, err := vac.rpc.DispatchSync(MethodIsSafeDomain, data) if err != nil { return nil, err } resp := &core.IsSafeDomainResponse{} err = json.Unmarshal(jsonResp, resp) if err != nil { return nil, err } return resp, nil } // NewPublisherServer creates a new server that wraps a CT publisher func NewPublisherServer(rpc Server, impl core.Publisher) (err error) { rpc.Handle(MethodSubmitToCT, func(req []byte) (response []byte, err error) { err = impl.SubmitToCT(req) return }) return nil } // PublisherClient is a client to communicate with the Publisher Authority type PublisherClient struct { rpc Client } // NewPublisherClient constructs an RPC client func NewPublisherClient(clientName string, amqpConf *cmd.AMQPConfig, stats statsd.Statter) (*PublisherClient, error) { client, err := NewAmqpRPCClient(clientName+"->Publisher", amqpConf, amqpConf.Publisher, stats) return &PublisherClient{rpc: client}, err } // SubmitToCT sends a request to submit a certifcate to CT logs func (pub PublisherClient) SubmitToCT(der []byte) (err error) { _, err = pub.rpc.DispatchSync(MethodSubmitToCT, der) return } // NewCertificateAuthorityServer constructs an RPC server // // CertificateAuthorityClient / Server // -> IssueCertificate func NewCertificateAuthorityServer(rpc Server, impl core.CertificateAuthority) (err error) { rpc.Handle(MethodIssueCertificate, func(req []byte) (response []byte, err error) { var icReq issueCertificateRequest err = json.Unmarshal(req, &icReq) if err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodIssueCertificate, err, req) return } csr, err := x509.ParseCertificateRequest(icReq.Bytes) if err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodIssueCertificate, err, req) return } cert, err := impl.IssueCertificate(*csr, icReq.RegID) if err != nil { return } response, err = json.Marshal(cert) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodGetRegistration, err, req) return } return }) rpc.Handle(MethodRevokeCertificate, func(req []byte) (response []byte, err error) { var revokeReq revokeCertificateRequest err = json.Unmarshal(req, &revokeReq) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodRevokeCertificate, err, req) return } err = impl.RevokeCertificate(revokeReq.Serial, revokeReq.ReasonCode) return }) rpc.Handle(MethodGenerateOCSP, func(req []byte) (response []byte, err error) { var xferObj core.OCSPSigningRequest err = json.Unmarshal(req, &xferObj) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodGenerateOCSP, err, req) return } response, err = impl.GenerateOCSP(xferObj) if err != nil { return } return }) return nil } // CertificateAuthorityClient is a client to communicate with the CA. type CertificateAuthorityClient struct { rpc Client } // NewCertificateAuthorityClient constructs an RPC client func NewCertificateAuthorityClient(clientName string, amqpConf *cmd.AMQPConfig, stats statsd.Statter) (*CertificateAuthorityClient, error) { client, err := NewAmqpRPCClient(clientName+"->CA", amqpConf, amqpConf.CA, stats) return &CertificateAuthorityClient{rpc: client}, err } // IssueCertificate sends a request to issue a certificate func (cac CertificateAuthorityClient) IssueCertificate(csr x509.CertificateRequest, regID int64) (cert core.Certificate, err error) { var icReq issueCertificateRequest icReq.Bytes = csr.Raw icReq.RegID = regID data, err := json.Marshal(icReq) if err != nil { return } jsonResponse, err := cac.rpc.DispatchSync(MethodIssueCertificate, data) if err != nil { return } err = json.Unmarshal(jsonResponse, &cert) return } // RevokeCertificate sends a request to revoke a certificate func (cac CertificateAuthorityClient) RevokeCertificate(serial string, reasonCode core.RevocationCode) (err error) { var revokeReq revokeCertificateRequest revokeReq.Serial = serial revokeReq.ReasonCode = reasonCode data, err := json.Marshal(revokeReq) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodRevokeCertificate, err, revokeReq) return } _, err = cac.rpc.DispatchSync(MethodRevokeCertificate, data) return } // GenerateOCSP sends a request to generate an OCSP response func (cac CertificateAuthorityClient) GenerateOCSP(signRequest core.OCSPSigningRequest) (resp []byte, err error) { data, err := json.Marshal(signRequest) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodGenerateOCSP, err, signRequest) return } resp, err = cac.rpc.DispatchSync(MethodGenerateOCSP, data) if err != nil { return } if len(resp) < 1 { err = fmt.Errorf("Failure at Signer") return } return } // NewStorageAuthorityServer constructs an RPC server func NewStorageAuthorityServer(rpc Server, impl core.StorageAuthority) error { rpc.Handle(MethodUpdateRegistration, func(req []byte) (response []byte, err error) { var reg core.Registration if err = json.Unmarshal(req, ®); err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodUpdateRegistration, err, req) return } err = impl.UpdateRegistration(reg) return }) rpc.Handle(MethodGetRegistration, func(req []byte) (response []byte, err error) { var grReq getRegistrationRequest err = json.Unmarshal(req, &grReq) if err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodGetRegistration, err, req) return } reg, err := impl.GetRegistration(grReq.ID) if err != nil { return } response, err = json.Marshal(reg) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodGetRegistration, err, req) return } return }) rpc.Handle(MethodGetRegistrationByKey, func(req []byte) (response []byte, err error) { var jwk jose.JsonWebKey if err = json.Unmarshal(req, &jwk); err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodGetRegistrationByKey, err, req) return } reg, err := impl.GetRegistrationByKey(jwk) if err != nil { return } response, err = json.Marshal(reg) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodGetRegistrationByKey, err, req) return } return }) rpc.Handle(MethodGetAuthorization, func(req []byte) (response []byte, err error) { authz, err := impl.GetAuthorization(string(req)) if err != nil { return } response, err = json.Marshal(authz) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodGetAuthorization, err, req) return } return }) rpc.Handle(MethodGetAuthorizationsByDomain, func(req []byte) (response []byte, err error) { ident := core.AcmeIdentifier{} err = json.Unmarshal(req, &ident) if err != nil { return } authz, err := impl.GetAuthorizationsByDomain(ident) if err != nil { return } response, err = json.Marshal(authz) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodGetAuthorizationsByDomain, err, req) return } return }) rpc.Handle(MethodGetLatestValidAuthorization, func(req []byte) (response []byte, err error) { var lvar latestValidAuthorizationRequest if err = json.Unmarshal(req, &lvar); err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodNewAuthorization, err, req) return } authz, err := impl.GetLatestValidAuthorization(lvar.RegID, lvar.Identifier) if err != nil { return } response, err = json.Marshal(authz) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodGetLatestValidAuthorization, err, req) return } return }) rpc.Handle(MethodAddCertificate, func(req []byte) (response []byte, err error) { var acReq addCertificateRequest err = json.Unmarshal(req, &acReq) if err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodAddCertificate, err, req) return } id, err := impl.AddCertificate(acReq.Bytes, acReq.RegID) if err != nil { return } response = []byte(id) return }) rpc.Handle(MethodNewRegistration, func(req []byte) (response []byte, err error) { var registration core.Registration err = json.Unmarshal(req, ®istration) if err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodNewRegistration, err, req) return } output, err := impl.NewRegistration(registration) if err != nil { return } response, err = json.Marshal(output) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodNewRegistration, err, req) return } return }) rpc.Handle(MethodNewPendingAuthorization, func(req []byte) (response []byte, err error) { var authz core.Authorization if err = json.Unmarshal(req, &authz); err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodNewPendingAuthorization, err, req) return } output, err := impl.NewPendingAuthorization(authz) if err != nil { return } response, err = json.Marshal(output) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodNewPendingAuthorization, err, req) return } return }) rpc.Handle(MethodUpdatePendingAuthorization, func(req []byte) (response []byte, err error) { var authz core.Authorization if err = json.Unmarshal(req, &authz); err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodUpdatePendingAuthorization, err, req) return } err = impl.UpdatePendingAuthorization(authz) return }) rpc.Handle(MethodFinalizeAuthorization, func(req []byte) (response []byte, err error) { var authz core.Authorization if err = json.Unmarshal(req, &authz); err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodFinalizeAuthorization, err, req) return } err = impl.FinalizeAuthorization(authz) return }) rpc.Handle(MethodRevokeAuthorization, func(req []byte) (response []byte, err error) { err = impl.RevokeAuthorization(string(req)) return }) rpc.Handle(MethodGetCertificate, func(req []byte) (response []byte, err error) { cert, err := impl.GetCertificate(string(req)) if err != nil { return } jsonResponse, err := json.Marshal(cert) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodGetCertificate, err, req) return } return jsonResponse, nil }) rpc.Handle(MethodGetCertificateStatus, func(req []byte) (response []byte, err error) { status, err := impl.GetCertificateStatus(string(req)) if err != nil { return } response, err = json.Marshal(status) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodGetCertificateStatus, err, req) return } return }) rpc.Handle(MethodMarkCertificateRevoked, func(req []byte) (response []byte, err error) { var mcrReq markCertificateRevokedRequest if err = json.Unmarshal(req, &mcrReq); err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodMarkCertificateRevoked, err, req) return } err = impl.MarkCertificateRevoked(mcrReq.Serial, mcrReq.ReasonCode) return }) rpc.Handle(MethodUpdateOCSP, func(req []byte) (response []byte, err error) { var updateOCSPReq updateOCSPRequest if err = json.Unmarshal(req, &updateOCSPReq); err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodUpdateOCSP, err, req) return } err = impl.UpdateOCSP(updateOCSPReq.Serial, updateOCSPReq.OCSPResponse) return }) rpc.Handle(MethodAlreadyDeniedCSR, func(req []byte) (response []byte, err error) { var adcReq alreadyDeniedCSRReq err = json.Unmarshal(req, &adcReq) if err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodAlreadyDeniedCSR, err, req) return } exists, err := impl.AlreadyDeniedCSR(adcReq.Names) if err != nil { return } if exists { response = []byte{1} } else { response = []byte{0} } return }) rpc.Handle(MethodCountCertificatesRange, func(req []byte) (response []byte, err error) { var cReq countRequest err = json.Unmarshal(req, &cReq) if err != nil { return } count, err := impl.CountCertificatesRange(cReq.Start, cReq.End) if err != nil { return } return json.Marshal(count) }) rpc.Handle(MethodCountCertificatesByNames, func(req []byte) (response []byte, err error) { var cReq countCertificatesByNamesRequest err = json.Unmarshal(req, &cReq) if err != nil { return } counts, err := impl.CountCertificatesByNames(cReq.Names, cReq.Earliest, cReq.Latest) if err != nil { return } return json.Marshal(counts) }) rpc.Handle(MethodCountRegistrationsByIP, func(req []byte) (response []byte, err error) { var cReq countRegistrationsByIPRequest err = json.Unmarshal(req, &cReq) if err != nil { return } count, err := impl.CountRegistrationsByIP(cReq.IP, cReq.Earliest, cReq.Latest) if err != nil { return } return json.Marshal(count) }) rpc.Handle(MethodCountPendingAuthorizations, func(req []byte) (response []byte, err error) { var cReq countPendingAuthorizationsRequest err = json.Unmarshal(req, &cReq) if err != nil { return } count, err := impl.CountPendingAuthorizations(cReq.RegID) if err != nil { return } return json.Marshal(count) }) rpc.Handle(MethodGetSCTReceipt, func(req []byte) (response []byte, err error) { var gsctReq struct { Serial string LogID string } err = json.Unmarshal(req, &gsctReq) if err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodGetSCTReceipt, err, req) return } sct, err := impl.GetSCTReceipt(gsctReq.Serial, gsctReq.LogID) jsonResponse, err := json.Marshal(sct) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodGetSCTReceipt, err, req) return } return jsonResponse, nil }) rpc.Handle(MethodAddSCTReceipt, func(req []byte) (response []byte, err error) { var sct core.SignedCertificateTimestamp err = json.Unmarshal(req, &sct) if err != nil { // AUDIT[ Improper Messages ] 0786b6f2-91ca-4f48-9883-842a19084c64 improperMessage(MethodAddSCTReceipt, err, req) return } err = impl.AddSCTReceipt(core.SignedCertificateTimestamp(sct)) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 errorCondition(MethodAddSCTReceipt, err, req) return } return nil, nil }) return nil } // StorageAuthorityClient is a client to communicate with the Storage Authority type StorageAuthorityClient struct { rpc Client } // NewStorageAuthorityClient constructs an RPC client func NewStorageAuthorityClient(clientName string, amqpConf *cmd.AMQPConfig, stats statsd.Statter) (*StorageAuthorityClient, error) { client, err := NewAmqpRPCClient(clientName+"->SA", amqpConf, amqpConf.SA, stats) return &StorageAuthorityClient{rpc: client}, err } // GetRegistration sends a request to get a registration by ID func (cac StorageAuthorityClient) GetRegistration(id int64) (reg core.Registration, err error) { var grReq getRegistrationRequest grReq.ID = id data, err := json.Marshal(grReq) if err != nil { return } jsonReg, err := cac.rpc.DispatchSync(MethodGetRegistration, data) if err != nil { return } err = json.Unmarshal(jsonReg, ®) return } // GetRegistrationByKey sends a request to get a registration by JWK func (cac StorageAuthorityClient) GetRegistrationByKey(key jose.JsonWebKey) (reg core.Registration, err error) { jsonKey, err := key.MarshalJSON() if err != nil { return } jsonReg, err := cac.rpc.DispatchSync(MethodGetRegistrationByKey, jsonKey) if err != nil { return } err = json.Unmarshal(jsonReg, ®) return } // GetAuthorization sends a request to get an Authorization by ID func (cac StorageAuthorityClient) GetAuthorization(id string) (authz core.Authorization, err error) { jsonAuthz, err := cac.rpc.DispatchSync(MethodGetAuthorization, []byte(id)) if err != nil { return } err = json.Unmarshal(jsonAuthz, &authz) return } // GetAuthorizationsByDomain sends a request to get all Authorizations for a domain func (cac StorageAuthorityClient) GetAuthorizationsByDomain(ident core.AcmeIdentifier) (authz []core.Authorization, err error) { jsonData, err := json.Marshal(ident) if err != nil { return } jsonAuthz, err := cac.rpc.DispatchSync(MethodGetAuthorizationsByDomain, jsonData) if err != nil { return } err = json.Unmarshal(jsonAuthz, &authz) return } // GetLatestValidAuthorization sends a request to get an Authorization by RegID, Identifier func (cac StorageAuthorityClient) GetLatestValidAuthorization(registrationID int64, identifier core.AcmeIdentifier) (authz core.Authorization, err error) { var lvar latestValidAuthorizationRequest lvar.RegID = registrationID lvar.Identifier = identifier data, err := json.Marshal(lvar) if err != nil { return } jsonAuthz, err := cac.rpc.DispatchSync(MethodGetLatestValidAuthorization, data) if err != nil { return } err = json.Unmarshal(jsonAuthz, &authz) return } // GetCertificate sends a request to get a Certificate by ID func (cac StorageAuthorityClient) GetCertificate(id string) (cert core.Certificate, err error) { jsonCert, err := cac.rpc.DispatchSync(MethodGetCertificate, []byte(id)) if err != nil { return } err = json.Unmarshal(jsonCert, &cert) return } // GetCertificateStatus sends a request to obtain the current status of a // certificate by ID func (cac StorageAuthorityClient) GetCertificateStatus(id string) (status core.CertificateStatus, err error) { jsonStatus, err := cac.rpc.DispatchSync(MethodGetCertificateStatus, []byte(id)) if err != nil { return } err = json.Unmarshal(jsonStatus, &status) return } // MarkCertificateRevoked sends a request to mark a certificate as revoked func (cac StorageAuthorityClient) MarkCertificateRevoked(serial string, reasonCode core.RevocationCode) (err error) { var mcrReq markCertificateRevokedRequest mcrReq.Serial = serial mcrReq.ReasonCode = reasonCode data, err := json.Marshal(mcrReq) if err != nil { return } _, err = cac.rpc.DispatchSync(MethodMarkCertificateRevoked, data) return } // UpdateOCSP sends a request to store an updated OCSP response func (cac StorageAuthorityClient) UpdateOCSP(serial string, ocspResponse []byte) (err error) { var updateOCSPReq updateOCSPRequest updateOCSPReq.Serial = serial updateOCSPReq.OCSPResponse = ocspResponse data, err := json.Marshal(updateOCSPReq) if err != nil { return } _, err = cac.rpc.DispatchSync(MethodUpdateOCSP, data) return } // UpdateRegistration sends a request to store an updated registration func (cac StorageAuthorityClient) UpdateRegistration(reg core.Registration) (err error) { jsonReg, err := json.Marshal(reg) if err != nil { return } _, err = cac.rpc.DispatchSync(MethodUpdateRegistration, jsonReg) return } // NewRegistration sends a request to store a new registration func (cac StorageAuthorityClient) NewRegistration(reg core.Registration) (output core.Registration, err error) { jsonReg, err := json.Marshal(reg) if err != nil { err = errors.New("NewRegistration RPC failed") return } response, err := cac.rpc.DispatchSync(MethodNewRegistration, jsonReg) if err != nil { return } err = json.Unmarshal(response, &output) if err != nil { err = errors.New("NewRegistration RPC failed") return } return output, nil } // NewPendingAuthorization sends a request to store a pending authorization func (cac StorageAuthorityClient) NewPendingAuthorization(authz core.Authorization) (output core.Authorization, err error) { jsonAuthz, err := json.Marshal(authz) if err != nil { return } response, err := cac.rpc.DispatchSync(MethodNewPendingAuthorization, jsonAuthz) if err != nil { return } err = json.Unmarshal(response, &output) if err != nil { err = errors.New("NewRegistration RPC failed") return } return } // UpdatePendingAuthorization sends a request to update the data in a pending // authorization func (cac StorageAuthorityClient) UpdatePendingAuthorization(authz core.Authorization) (err error) { jsonAuthz, err := json.Marshal(authz) if err != nil { return } _, err = cac.rpc.DispatchSync(MethodUpdatePendingAuthorization, jsonAuthz) return } // FinalizeAuthorization sends a request to finalize an authorization (convert // from pending) func (cac StorageAuthorityClient) FinalizeAuthorization(authz core.Authorization) (err error) { jsonAuthz, err := json.Marshal(authz) if err != nil { return } _, err = cac.rpc.DispatchSync(MethodFinalizeAuthorization, jsonAuthz) return } // RevokeAuthorization sends a request to revoke a pending or finalized authorization func (cac StorageAuthorityClient) RevokeAuthorization(id string) (err error) { _, err = cac.rpc.DispatchSync(MethodRevokeAuthorization, []byte(id)) return } // AddCertificate sends a request to record the issuance of a certificate func (cac StorageAuthorityClient) AddCertificate(cert []byte, regID int64) (id string, err error) { var acReq addCertificateRequest acReq.Bytes = cert acReq.RegID = regID data, err := json.Marshal(acReq) if err != nil { return } response, err := cac.rpc.DispatchSync(MethodAddCertificate, data) if err != nil { return } id = string(response) return } // AlreadyDeniedCSR sends a request to search for denied names func (cac StorageAuthorityClient) AlreadyDeniedCSR(names []string) (exists bool, err error) { var adcReq alreadyDeniedCSRReq adcReq.Names = names data, err := json.Marshal(adcReq) if err != nil { return } response, err := cac.rpc.DispatchSync(MethodAlreadyDeniedCSR, data) if err != nil { return } switch response[0] { case 0: exists = false case 1: exists = true } return } // CountCertificatesRange sends a request to count the number of certificates // issued in a certain time range func (cac StorageAuthorityClient) CountCertificatesRange(start, end time.Time) (count int64, err error) { var cReq countRequest cReq.Start, cReq.End = start, end data, err := json.Marshal(cReq) if err != nil { return } response, err := cac.rpc.DispatchSync(MethodCountCertificatesRange, data) if err != nil { return } err = json.Unmarshal(response, &count) return } // CountCertificatesByNames calls CountCertificatesRange on the remote // StorageAuthority. func (cac StorageAuthorityClient) CountCertificatesByNames(names []string, earliest, latest time.Time) (counts map[string]int, err error) { var cReq countCertificatesByNamesRequest cReq.Names, cReq.Earliest, cReq.Latest = names, earliest, latest data, err := json.Marshal(cReq) if err != nil { return } response, err := cac.rpc.DispatchSync(MethodCountCertificatesByNames, data) if err != nil { return } err = json.Unmarshal(response, &counts) return } // CountRegistrationsByIP calls CountRegistrationsByIP on the remote // StorageAuthority. func (cac StorageAuthorityClient) CountRegistrationsByIP(ip net.IP, earliest, latest time.Time) (count int, err error) { var cReq countRegistrationsByIPRequest cReq.IP, cReq.Earliest, cReq.Latest = ip, earliest, latest data, err := json.Marshal(cReq) if err != nil { return } response, err := cac.rpc.DispatchSync(MethodCountRegistrationsByIP, data) if err != nil { return } err = json.Unmarshal(response, &count) return } // CountPendingAuthorizations calls CountPendingAuthorizations on the remote // StorageAuthority. func (cac StorageAuthorityClient) CountPendingAuthorizations(regID int64) (count int, err error) { var cReq countPendingAuthorizationsRequest cReq.RegID = regID data, err := json.Marshal(cReq) if err != nil { return } response, err := cac.rpc.DispatchSync(MethodCountPendingAuthorizations, data) if err != nil { return } err = json.Unmarshal(response, &count) return } // GetSCTReceipt retrieves an SCT according to the serial number of a certificate // and the logID of the log to which it was submitted. func (cac StorageAuthorityClient) GetSCTReceipt(serial string, logID string) (receipt core.SignedCertificateTimestamp, err error) { var gsctReq struct { Serial string LogID string } gsctReq.Serial = serial gsctReq.LogID = logID data, err := json.Marshal(gsctReq) if err != nil { return } response, err := cac.rpc.DispatchSync(MethodGetSCTReceipt, data) if err != nil { return } err = json.Unmarshal(response, receipt) return } // AddSCTReceipt adds a new SCT to the database. func (cac StorageAuthorityClient) AddSCTReceipt(sct core.SignedCertificateTimestamp) (err error) { data, err := json.Marshal(sct) if err != nil { return } _, err = cac.rpc.DispatchSync(MethodAddSCTReceipt, data) return }