// IssueCertificate attempts to convert a CSR into a signed Certificate, while // enforcing all policies. func (ca *CertificateAuthorityImpl) IssueCertificate(csr x509.CertificateRequest, regID int64) (core.Certificate, error) { emptyCert := core.Certificate{} var err error key, ok := csr.PublicKey.(crypto.PublicKey) if !ok { err = fmt.Errorf("Invalid public key in CSR.") // AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c ca.log.AuditErr(err) return emptyCert, err } if err = core.GoodKey(key); err != nil { err = fmt.Errorf("Invalid public key in CSR: %s", err.Error()) // AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c ca.log.AuditErr(err) return emptyCert, err } if badSignatureAlgorithms[csr.SignatureAlgorithm] { err = fmt.Errorf("Invalid signature algorithm in CSR") // AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c ca.log.AuditErr(err) return emptyCert, err } // Pull hostnames from CSR // Authorization is checked by the RA commonName := "" hostNames := make([]string, len(csr.DNSNames)) copy(hostNames, csr.DNSNames) if len(csr.Subject.CommonName) > 0 { commonName = csr.Subject.CommonName hostNames = append(hostNames, csr.Subject.CommonName) } else if len(hostNames) > 0 { commonName = hostNames[0] } else { err = fmt.Errorf("Cannot issue a certificate without a hostname.") // AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c ca.log.AuditErr(err) return emptyCert, err } // Collapse any duplicate names. Note that this operation may re-order the names hostNames = core.UniqueNames(hostNames) if ca.MaxNames > 0 && len(hostNames) > ca.MaxNames { err = fmt.Errorf("Certificate request has %d > %d names", len(hostNames), ca.MaxNames) ca.log.WarningErr(err) return emptyCert, err } // Verify that names are allowed by policy identifier := core.AcmeIdentifier{Type: core.IdentifierDNS, Value: commonName} if err = ca.PA.WillingToIssue(identifier); err != nil { err = fmt.Errorf("Policy forbids issuing for name %s", commonName) // AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c ca.log.AuditErr(err) return emptyCert, err } for _, name := range hostNames { identifier = core.AcmeIdentifier{Type: core.IdentifierDNS, Value: name} if err = ca.PA.WillingToIssue(identifier); err != nil { err = fmt.Errorf("Policy forbids issuing for name %s", name) // AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c ca.log.AuditErr(err) return emptyCert, err } } notAfter := ca.Clk.Now().Add(ca.ValidityPeriod) if ca.NotAfter.Before(notAfter) { // AUDIT[ Certificate Requests ] 11917fa4-10ef-4e0d-9105-bacbe7836a3c err = errors.New("Cannot issue a certificate that expires after the intermediate certificate.") ca.log.AuditErr(err) return emptyCert, err } // Convert the CSR to PEM csrPEM := string(pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE REQUEST", Bytes: csr.Raw, })) // Get the next serial number tx, err := ca.DB.Begin() if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 ca.log.AuditErr(err) return emptyCert, err } serialDec, err := ca.DB.IncrementAndGetSerial(tx) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 ca.log.Audit(fmt.Sprintf("Serial increment failed, rolling back: err=[%v]", err)) tx.Rollback() return emptyCert, err } serialHex := fmt.Sprintf("%02X%014X", ca.Prefix, serialDec) // Send the cert off for signing req := signer.SignRequest{ Request: csrPEM, Profile: ca.profile, Hosts: hostNames, Subject: &signer.Subject{ CN: commonName, }, SerialSeq: serialHex, } certPEM, err := ca.Signer.Sign(req) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 ca.log.Audit(fmt.Sprintf("Signer failed, rolling back: serial=[%s] err=[%v]", serialHex, err)) tx.Rollback() return emptyCert, err } if len(certPEM) == 0 { err = fmt.Errorf("No certificate returned by server") // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 ca.log.Audit(fmt.Sprintf("PEM empty from Signer, rolling back: serial=[%s] err=[%v]", serialHex, err)) tx.Rollback() return emptyCert, err } block, _ := pem.Decode(certPEM) if block == nil || block.Type != "CERTIFICATE" { err = fmt.Errorf("Invalid certificate value returned") // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 ca.log.Audit(fmt.Sprintf("PEM decode error, aborting and rolling back issuance: pem=[%s] err=[%v]", certPEM, err)) tx.Rollback() return emptyCert, err } certDER := block.Bytes cert := core.Certificate{ DER: certDER, } // This is one last check for uncaught errors if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 ca.log.Audit(fmt.Sprintf("Uncaught error, aborting and rolling back issuance: pem=[%s] err=[%v]", certPEM, err)) tx.Rollback() return emptyCert, err } // Store the cert with the certificate authority, if provided _, err = ca.SA.AddCertificate(certDER, regID) if err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 ca.log.Audit(fmt.Sprintf("Failed RPC to store at SA, orphaning certificate: pem=[%s] err=[%v]", certPEM, err)) tx.Rollback() return emptyCert, err } if err = tx.Commit(); err != nil { // AUDIT[ Error Conditions ] 9cc4d537-8534-4970-8665-4b382abe82f3 ca.log.Audit(fmt.Sprintf("Failed to commit, orphaning certificate: pem=[%s] err=[%v]", certPEM, err)) return emptyCert, err } // Attempt to generate the OCSP Response now. If this raises an error, it is // logged but is not returned to the caller, as an error at this point does // not constitute an issuance failure. certObj, err := x509.ParseCertificate(certDER) if err != nil { ca.log.Warning(fmt.Sprintf("Post-Issuance OCSP failed parsing Certificate: %s", err)) return cert, nil } serial := core.SerialToString(certObj.SerialNumber) signRequest := ocsp.SignRequest{ Certificate: certObj, Status: string(core.OCSPStatusGood), } ocspResponse, err := ca.OCSPSigner.Sign(signRequest) if err != nil { ca.log.Warning(fmt.Sprintf("Post-Issuance OCSP failed signing: %s", err)) return cert, nil } err = ca.SA.UpdateOCSP(serial, ocspResponse) if err != nil { ca.log.Warning(fmt.Sprintf("Post-Issuance OCSP failed storing: %s", err)) return cert, nil } // 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 }
// MatchesCSR tests the contents of a generated certificate to make sure // that the PublicKey, CommonName, and DNSNames match those provided in // the CSR that was used to generate the certificate. It also checks the // following fields for: // * notBefore is not more than 24 hours ago // * BasicConstraintsValid is true // * IsCA is false // * ExtKeyUsage only contains ExtKeyUsageServerAuth & ExtKeyUsageClientAuth // * Subject only contains CommonName & Names func (ra *RegistrationAuthorityImpl) MatchesCSR( cert core.Certificate, csr *x509.CertificateRequest) (err error) { parsedCertificate, err := x509.ParseCertificate([]byte(cert.DER)) if err != nil { return } // Check issued certificate matches what was expected from the CSR hostNames := make([]string, len(csr.DNSNames)) copy(hostNames, csr.DNSNames) if len(csr.Subject.CommonName) > 0 { hostNames = append(hostNames, csr.Subject.CommonName) } hostNames = core.UniqueNames(hostNames) if !core.KeyDigestEquals(parsedCertificate.PublicKey, csr.PublicKey) { err = core.InternalServerError("Generated certificate public key doesn't match CSR public key") return } if len(csr.Subject.CommonName) > 0 && parsedCertificate.Subject.CommonName != csr.Subject.CommonName { err = core.InternalServerError("Generated certificate CommonName doesn't match CSR CommonName") return } // Sort both slices of names before comparison. parsedNames := parsedCertificate.DNSNames sort.Strings(parsedNames) sort.Strings(hostNames) if !reflect.DeepEqual(parsedNames, hostNames) { err = core.InternalServerError("Generated certificate DNSNames don't match CSR DNSNames") return } if !reflect.DeepEqual(parsedCertificate.IPAddresses, csr.IPAddresses) { err = core.InternalServerError("Generated certificate IPAddresses don't match CSR IPAddresses") return } if !reflect.DeepEqual(parsedCertificate.EmailAddresses, csr.EmailAddresses) { err = core.InternalServerError("Generated certificate EmailAddresses don't match CSR EmailAddresses") return } if len(parsedCertificate.Subject.Country) > 0 || len(parsedCertificate.Subject.Organization) > 0 || len(parsedCertificate.Subject.OrganizationalUnit) > 0 || len(parsedCertificate.Subject.Locality) > 0 || len(parsedCertificate.Subject.Province) > 0 || len(parsedCertificate.Subject.StreetAddress) > 0 || len(parsedCertificate.Subject.PostalCode) > 0 || len(parsedCertificate.Subject.SerialNumber) > 0 { err = core.InternalServerError("Generated certificate Subject contains fields other than CommonName or Names") return } now := ra.clk.Now() if now.Sub(parsedCertificate.NotBefore) > time.Hour*24 { err = core.InternalServerError(fmt.Sprintf("Generated certificate is back dated %s", now.Sub(parsedCertificate.NotBefore))) return } if !parsedCertificate.BasicConstraintsValid { err = core.InternalServerError("Generated certificate doesn't have basic constraints set") return } if parsedCertificate.IsCA { err = core.InternalServerError("Generated certificate can sign other certificates") return } if !reflect.DeepEqual(parsedCertificate.ExtKeyUsage, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}) { err = core.InternalServerError("Generated certificate doesn't have correct key usage extensions") return } return }