// NewCertificate requests the issuance of a certificate. func (ra *RegistrationAuthorityImpl) NewCertificate(ctx context.Context, req core.CertificateRequest, regID int64) (cert core.Certificate, err error) { emptyCert := core.Certificate{} var logEventResult string // Assume the worst logEventResult = "error" // Construct the log event logEvent := certificateRequestEvent{ ID: core.NewToken(), Requester: regID, RequestMethod: "online", RequestTime: ra.clk.Now(), } // No matter what, log the request defer func() { // AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c ra.log.AuditObject(fmt.Sprintf("Certificate request - %s", logEventResult), logEvent) }() if regID <= 0 { err = core.MalformedRequestError(fmt.Sprintf("Invalid registration ID: %d", regID)) return emptyCert, err } registration, err := ra.SA.GetRegistration(ctx, regID) if err != nil { logEvent.Error = err.Error() return emptyCert, err } // Verify the CSR csr := req.CSR if err := csrlib.VerifyCSR(csr, ra.maxNames, &ra.keyPolicy, ra.PA, ra.forceCNFromSAN, regID); err != nil { err = core.MalformedRequestError(err.Error()) return emptyCert, err } logEvent.CommonName = csr.Subject.CommonName logEvent.Names = csr.DNSNames // Validate that authorization key is authorized for all domains names := make([]string, len(csr.DNSNames)) copy(names, csr.DNSNames) if len(names) == 0 { err = core.UnauthorizedError("CSR has no names in it") logEvent.Error = err.Error() return emptyCert, err } if core.KeyDigestEquals(csr.PublicKey, registration.Key) { err = core.MalformedRequestError("Certificate public key must be different than account key") return emptyCert, err } // Check rate limits before checking authorizations. If someone is unable to // issue a cert due to rate limiting, we don't want to tell them to go get the // necessary authorizations, only to later fail the rate limit check. err = ra.checkLimits(ctx, names, registration.ID) if err != nil { logEvent.Error = err.Error() return emptyCert, err } err = ra.checkAuthorizations(ctx, names, ®istration) if err != nil { logEvent.Error = err.Error() return emptyCert, err } // Mark that we verified the CN and SANs logEvent.VerifiedFields = []string{"subject.commonName", "subjectAltName"} // Create the certificate and log the result if cert, err = ra.CA.IssueCertificate(ctx, *csr, regID); err != nil { logEvent.Error = err.Error() return emptyCert, err } err = ra.MatchesCSR(cert, csr) if err != nil { logEvent.Error = err.Error() return emptyCert, err } parsedCertificate, err := x509.ParseCertificate([]byte(cert.DER)) if err != nil { // InternalServerError because the certificate from the CA should be // parseable. err = core.InternalServerError(err.Error()) logEvent.Error = err.Error() return emptyCert, err } logEvent.SerialNumber = core.SerialToString(parsedCertificate.SerialNumber) logEvent.CommonName = parsedCertificate.Subject.CommonName logEvent.NotBefore = parsedCertificate.NotBefore logEvent.NotAfter = parsedCertificate.NotAfter logEvent.ResponseTime = ra.clk.Now() logEventResult = "successful" ra.stats.Inc("RA.NewCertificates", 1, 1.0) return cert, nil }
// IssueCertificate attempts to convert a CSR into a signed Certificate, while // enforcing all policies. Names (domains) in the CertificateRequest will be // lowercased before storage. // Currently it will always sign with the defaultIssuer. func (ca *CertificateAuthorityImpl) IssueCertificate(ctx context.Context, csr x509.CertificateRequest, regID int64) (core.Certificate, error) { emptyCert := core.Certificate{} if err := csrlib.VerifyCSR(&csr, ca.maxNames, &ca.keyPolicy, ca.PA, ca.forceCNFromSAN, regID); err != nil { // AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c ca.log.AuditErr(err.Error()) return emptyCert, core.MalformedRequestError(err.Error()) } requestedExtensions, err := ca.extensionsFromCSR(&csr) if err != nil { return emptyCert, err } issuer := ca.defaultIssuer notAfter := ca.clk.Now().Add(ca.validityPeriod) if issuer.cert.NotAfter.Before(notAfter) { err = core.InternalServerError("Cannot issue a certificate that expires after the issuer certificate.") // AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c ca.log.AuditErr(err.Error()) return emptyCert, err } // Convert the CSR to PEM csrPEM := string(pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE REQUEST", Bytes: csr.Raw, })) // We want 136 bits of random number, plus an 8-bit instance id prefix. const randBits = 136 serialBytes := make([]byte, randBits/8+1) serialBytes[0] = byte(ca.prefix) _, err = rand.Read(serialBytes[1:]) if err != nil { err = core.InternalServerError(err.Error()) // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 ca.log.AuditErr(fmt.Sprintf("Serial randomness failed, err=[%v]", err)) return emptyCert, err } serialBigInt := big.NewInt(0) serialBigInt = serialBigInt.SetBytes(serialBytes) serialHex := core.SerialToString(serialBigInt) var profile string switch csr.PublicKey.(type) { case *rsa.PublicKey: profile = ca.rsaProfile case *ecdsa.PublicKey: profile = ca.ecdsaProfile default: err = core.InternalServerError(fmt.Sprintf("unsupported key type %T", csr.PublicKey)) // AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c ca.log.AuditErr(err.Error()) return emptyCert, err } // Send the cert off for signing req := signer.SignRequest{ Request: csrPEM, Profile: profile, Hosts: csr.DNSNames, Subject: &signer.Subject{ CN: csr.Subject.CommonName, }, Serial: serialBigInt, Extensions: requestedExtensions, } if !ca.forceCNFromSAN { req.Subject.SerialNumber = serialHex } ca.log.AuditInfo(fmt.Sprintf("Signing: serial=[%s] names=[%s] csr=[%s]", serialHex, strings.Join(csr.DNSNames, ", "), csrPEM)) certPEM, err := issuer.eeSigner.Sign(req) ca.noteSignError(err) if err != nil { err = core.InternalServerError(err.Error()) // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 ca.log.AuditErr(fmt.Sprintf("Signing failed: serial=[%s] err=[%v]", serialHex, err)) return emptyCert, err } ca.log.AuditInfo(fmt.Sprintf("Signing success: serial=[%s] names=[%s] csr=[%s] pem=[%s]", serialHex, strings.Join(csr.DNSNames, ", "), csrPEM, certPEM)) if len(certPEM) == 0 { err = core.InternalServerError("No certificate returned by server") // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 ca.log.AuditErr(fmt.Sprintf("PEM empty from Signer: serial=[%s] err=[%v]", serialHex, err)) return emptyCert, err } block, _ := pem.Decode(certPEM) if block == nil || block.Type != "CERTIFICATE" { err = core.InternalServerError("Invalid certificate value returned") // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 ca.log.AuditErr(fmt.Sprintf("PEM decode error, aborting: serial=[%s] pem=[%s] err=[%v]", serialHex, certPEM, err)) return emptyCert, err } certDER := block.Bytes cert := core.Certificate{ DER: certDER, } // This is one last check for uncaught errors if err != nil { err = core.InternalServerError(err.Error()) // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 ca.log.AuditErr(fmt.Sprintf("Uncaught error, aborting: serial=[%s] pem=[%s] err=[%v]", serialHex, certPEM, err)) return emptyCert, err } // Store the cert with the certificate authority, if provided _, err = ca.SA.AddCertificate(ctx, certDER, regID) if err != nil { err = core.InternalServerError(err.Error()) // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 ca.log.AuditErr(fmt.Sprintf( "Failed RPC to store at SA, orphaning certificate: serial=[%s] b64der=[%s] err=[%v], regID=[%d]", serialHex, base64.StdEncoding.EncodeToString(certDER), err, regID, )) return emptyCert, err } // Submit the certificate to any configured CT logs go func() { // since we don't want this method to be canceled if the parent context // expires pass a background context to it _ = ca.Publisher.SubmitToCT(context.Background(), certDER) }() // Do not return an err at this point; caller must know that the Certificate // was issued. (Also, it should be impossible for err to be non-nil here) return cert, nil }