// Generate creates a new CSR from a CertificateRequest structure and // an existing key. The KeyRequest field is ignored. func Generate(priv crypto.Signer, req *CertificateRequest) (csr []byte, err error) { sigAlgo := helpers.SignerAlgo(priv, crypto.SHA256) if sigAlgo == x509.UnknownSignatureAlgorithm { return nil, cferr.New(cferr.PrivateKeyError, cferr.Unavailable) } var tpl = x509.CertificateRequest{ Subject: req.Name(), SignatureAlgorithm: sigAlgo, } for i := range req.Hosts { if ip := net.ParseIP(req.Hosts[i]); ip != nil { tpl.IPAddresses = append(tpl.IPAddresses, ip) } else { tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i]) } } csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv) if err != nil { log.Errorf("failed to generate a CSR: %v", err) err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err) return } block := pem.Block{ Type: "CERTIFICATE REQUEST", Bytes: csr, } log.Info("encoded CSR") csr = pem.EncodeToMemory(&block) return }
// NewFromSigner creates a new root certificate from a crypto.Signer. func NewFromSigner(req *csr.CertificateRequest, priv crypto.Signer) (cert, csrPEM []byte, err error) { if req.CA != nil { if req.CA.Expiry != "" { CAPolicy.Default.ExpiryString = req.CA.Expiry CAPolicy.Default.Expiry, err = time.ParseDuration(req.CA.Expiry) if err != nil { return nil, nil, err } } if req.CA.PathLength != 0 { signer.MaxPathLen = req.CA.PathLength } } var sigAlgo x509.SignatureAlgorithm switch pub := priv.Public().(type) { case *rsa.PublicKey: bitLength := pub.N.BitLen() switch { case bitLength >= 4096: sigAlgo = x509.SHA512WithRSA case bitLength >= 3072: sigAlgo = x509.SHA384WithRSA case bitLength >= 2048: sigAlgo = x509.SHA256WithRSA default: sigAlgo = x509.SHA1WithRSA } case *ecdsa.PublicKey: switch pub.Curve { case elliptic.P521(): sigAlgo = x509.ECDSAWithSHA512 case elliptic.P384(): sigAlgo = x509.ECDSAWithSHA384 case elliptic.P256(): sigAlgo = x509.ECDSAWithSHA256 default: sigAlgo = x509.ECDSAWithSHA1 } default: sigAlgo = x509.UnknownSignatureAlgorithm } var tpl = x509.CertificateRequest{ Subject: req.Name(), SignatureAlgorithm: sigAlgo, } for i := range req.Hosts { if ip := net.ParseIP(req.Hosts[i]); ip != nil { tpl.IPAddresses = append(tpl.IPAddresses, ip) } else { tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i]) } } return signWithCSR(&tpl, priv) }
// normalizeCSR deduplicates and lowers the case of dNSNames and the subject CN. // If forceCNFromSAN is true it will also hoist a dNSName into the CN if it is empty. func normalizeCSR(csr *x509.CertificateRequest, forceCNFromSAN bool) { if forceCNFromSAN && csr.Subject.CommonName == "" { if len(csr.DNSNames) > 0 { csr.Subject.CommonName = csr.DNSNames[0] } } else if csr.Subject.CommonName != "" { csr.DNSNames = append(csr.DNSNames, csr.Subject.CommonName) } csr.Subject.CommonName = strings.ToLower(csr.Subject.CommonName) csr.DNSNames = core.UniqueLowerNames(csr.DNSNames) }
func CreateCertRequest(d *schema.ResourceData, meta interface{}) error { keyAlgoName := d.Get("key_algorithm").(string) var keyFunc keyParser var ok bool if keyFunc, ok = keyParsers[keyAlgoName]; !ok { return fmt.Errorf("invalid key_algorithm %#v", keyAlgoName) } keyBlock, _ := pem.Decode([]byte(d.Get("private_key_pem").(string))) if keyBlock == nil { return fmt.Errorf("no PEM block found in private_key_pem") } key, err := keyFunc(keyBlock.Bytes) if err != nil { return fmt.Errorf("failed to decode private_key_pem: %s", err) } subjectConfs := d.Get("subject").([]interface{}) if len(subjectConfs) != 1 { return fmt.Errorf("must have exactly one 'subject' block") } subjectConf := subjectConfs[0].(map[string]interface{}) subject, err := nameFromResourceData(subjectConf) if err != nil { return fmt.Errorf("invalid subject block: %s", err) } certReq := x509.CertificateRequest{ Subject: *subject, } dnsNamesI := d.Get("dns_names").([]interface{}) for _, nameI := range dnsNamesI { certReq.DNSNames = append(certReq.DNSNames, nameI.(string)) } ipAddressesI := d.Get("ip_addresses").([]interface{}) for _, ipStrI := range ipAddressesI { ip := net.ParseIP(ipStrI.(string)) if ip == nil { return fmt.Errorf("invalid IP address %#v", ipStrI.(string)) } certReq.IPAddresses = append(certReq.IPAddresses, ip) } certReqBytes, err := x509.CreateCertificateRequest(rand.Reader, &certReq, key) if err != nil { fmt.Errorf("Error creating certificate request: %s", err) } certReqPem := string(pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE REQUEST", Bytes: certReqBytes})) d.SetId(hashForState(string(certReqBytes))) d.Set("cert_request_pem", certReqPem) return nil }
func generateCsr(privateKey *rsa.PrivateKey, domain string, san []string) ([]byte, error) { template := x509.CertificateRequest{ Subject: pkix.Name{ CommonName: domain, }, } if len(san) > 0 { template.DNSNames = san } return x509.CreateCertificateRequest(rand.Reader, &template, privateKey) }
// VerifyCSR checks the validity of a x509.CertificateRequest. Before doing checks it normalizes // the CSR which lowers the case of DNS names and subject CN, and if forceCNFromSAN is true it // will hoist a DNS name into the CN if it is empty. func VerifyCSR(csr *x509.CertificateRequest, maxNames int, keyPolicy *goodkey.KeyPolicy, pa core.PolicyAuthority, forceCNFromSAN bool, regID int64) error { normalizeCSR(csr, forceCNFromSAN) key, ok := csr.PublicKey.(crypto.PublicKey) if !ok { return invalidPubKey } if err := keyPolicy.GoodKey(key); err != nil { return fmt.Errorf("invalid public key in CSR: %s", err) } if badSignatureAlgorithms[csr.SignatureAlgorithm] { // go1.6 provides a stringer for x509.SignatureAlgorithm but 1.5.x // does not return unsupportedSigAlg } if err := csr.CheckSignature(); err != nil { return invalidSig } if len(csr.EmailAddresses) > 0 { return invalidEmailPresent } if len(csr.IPAddresses) > 0 { return invalidIPPresent } if len(csr.DNSNames) == 0 && csr.Subject.CommonName == "" { return invalidNoDNS } if len(csr.Subject.CommonName) > maxCNLength { return fmt.Errorf("CN was longer than %d bytes", maxCNLength) } if maxNames > 0 && len(csr.DNSNames) > maxNames { return fmt.Errorf("CSR contains more than %d DNS names", maxNames) } badNames := []string{} for _, name := range csr.DNSNames { if err := pa.WillingToIssue(core.AcmeIdentifier{ Type: core.IdentifierDNS, Value: name, }); err != nil { badNames = append(badNames, fmt.Sprintf("%q", name)) } } if len(badNames) > 0 { return fmt.Errorf("policy forbids issuing for: %s", strings.Join(badNames, ", ")) } return nil }
func CreateCertRequest(d *schema.ResourceData, meta interface{}) error { key, err := parsePrivateKey(d, "private_key_pem", "key_algorithm") if err != nil { return err } subjectConfs := d.Get("subject").([]interface{}) if len(subjectConfs) != 1 { return fmt.Errorf("must have exactly one 'subject' block") } subjectConf := subjectConfs[0].(map[string]interface{}) subject, err := nameFromResourceData(subjectConf) if err != nil { return fmt.Errorf("invalid subject block: %s", err) } certReq := x509.CertificateRequest{ Subject: *subject, } dnsNamesI := d.Get("dns_names").([]interface{}) for _, nameI := range dnsNamesI { certReq.DNSNames = append(certReq.DNSNames, nameI.(string)) } ipAddressesI := d.Get("ip_addresses").([]interface{}) for _, ipStrI := range ipAddressesI { ip := net.ParseIP(ipStrI.(string)) if ip == nil { return fmt.Errorf("invalid IP address %#v", ipStrI.(string)) } certReq.IPAddresses = append(certReq.IPAddresses, ip) } certReqBytes, err := x509.CreateCertificateRequest(rand.Reader, &certReq, key) if err != nil { fmt.Errorf("Error creating certificate request: %s", err) } certReqPem := string(pem.EncodeToMemory(&pem.Block{Type: pemCertReqType, Bytes: certReqBytes})) d.SetId(hashForState(string(certReqBytes))) d.Set("cert_request_pem", certReqPem) return nil }
func generateCsr(privateKey crypto.PrivateKey, domain string, san []string, mustStaple bool) ([]byte, error) { template := x509.CertificateRequest{ Subject: pkix.Name{ CommonName: domain, }, } if len(san) > 0 { template.DNSNames = san } if mustStaple { template.Extensions = append(template.Extensions, pkix.Extension{ Id: tlsFeatureExtensionOID, Value: ocspMustStapleFeature, }) } return x509.CreateCertificateRequest(rand.Reader, &template, privateKey) }
// appendCAInfoToCSR appends CAConfig BasicConstraint extension to a CSR func appendCAInfoToCSR(reqConf *CAConfig, csr *x509.CertificateRequest) error { pathlen := reqConf.PathLength if pathlen == 0 && !reqConf.PathLenZero { pathlen = -1 } val, err := asn1.Marshal(BasicConstraints{true, pathlen}) if err != nil { return err } csr.ExtraExtensions = []pkix.Extension{ { Id: asn1.ObjectIdentifier{2, 5, 29, 19}, Value: val, Critical: true, }, } return nil }
// ParseRequest takes a certificate request and generates a key and // CSR from it. It does no validation -- caveat emptor. It will, // however, fail if the key request is not valid (i.e., an unsupported // curve or RSA key size). The lack of validation was specifically // chosen to allow the end user to define a policy and validate the // request appropriately before calling this function. func ParseRequest(req *CertificateRequest) (csr, key []byte, err error) { log.Info("received CSR") if req.KeyRequest == nil { req.KeyRequest = &KeyRequest{ Algo: DefaultKeyRequest.Algo, Size: DefaultKeyRequest.Size, } } log.Infof("generating key: %s-%d", req.KeyRequest.Algo, req.KeyRequest.Size) priv, err := req.KeyRequest.Generate() if err != nil { err = cferr.Wrap(cferr.PrivateKeyError, cferr.GenerationFailed, err) return } switch priv := priv.(type) { case *rsa.PrivateKey: key = x509.MarshalPKCS1PrivateKey(priv) block := pem.Block{ Type: "RSA PRIVATE KEY", Bytes: key, } key = pem.EncodeToMemory(&block) case *ecdsa.PrivateKey: key, err = x509.MarshalECPrivateKey(priv) if err != nil { err = cferr.Wrap(cferr.PrivateKeyError, cferr.Unknown, err) return } block := pem.Block{ Type: "EC PRIVATE KEY", Bytes: key, } key = pem.EncodeToMemory(&block) default: panic("Generate should have failed to produce a valid key.") } var tpl = x509.CertificateRequest{ Subject: req.Name(), SignatureAlgorithm: req.KeyRequest.SigAlgo(), } for i := range req.Hosts { if ip := net.ParseIP(req.Hosts[i]); ip != nil { tpl.IPAddresses = append(tpl.IPAddresses, ip) } else { tpl.DNSNames = append(tpl.DNSNames, req.Hosts[i]) } } csr, err = x509.CreateCertificateRequest(rand.Reader, &tpl, priv) if err != nil { log.Errorf("failed to generate a CSR: %v", err) err = cferr.Wrap(cferr.CSRError, cferr.BadRequest, err) return } block := pem.Block{ Type: "CERTIFICATE REQUEST", Bytes: csr, } log.Info("encoded CSR") csr = pem.EncodeToMemory(&block) return }
// Performs the heavy lifting of generating a certificate from a CSR. // Returns a ParsedCertBundle sans private keys. func signCertificate(creationInfo *creationBundle, csr *x509.CertificateRequest) (*certutil.ParsedCertBundle, error) { switch { case creationInfo == nil: return nil, errutil.UserError{Err: "nil creation info given to signCertificate"} case creationInfo.SigningBundle == nil: return nil, errutil.UserError{Err: "nil signing bundle given to signCertificate"} case csr == nil: return nil, errutil.UserError{Err: "nil csr given to signCertificate"} } err := csr.CheckSignature() if err != nil { return nil, errutil.UserError{Err: "request signature invalid"} } result := &certutil.ParsedCertBundle{} serialNumber, err := certutil.GenerateSerialNumber() if err != nil { return nil, err } marshaledKey, err := x509.MarshalPKIXPublicKey(csr.PublicKey) if err != nil { return nil, errutil.InternalError{Err: fmt.Sprintf("error marshalling public key: %s", err)} } subjKeyID := sha1.Sum(marshaledKey) subject := pkix.Name{ CommonName: creationInfo.CommonName, } certTemplate := &x509.Certificate{ SerialNumber: serialNumber, Subject: subject, NotBefore: time.Now().Add(-30 * time.Second), NotAfter: time.Now().Add(creationInfo.TTL), SubjectKeyId: subjKeyID[:], } switch creationInfo.SigningBundle.PrivateKeyType { case certutil.RSAPrivateKey: certTemplate.SignatureAlgorithm = x509.SHA256WithRSA case certutil.ECPrivateKey: certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256 } if creationInfo.UseCSRValues { certTemplate.Subject = csr.Subject certTemplate.DNSNames = csr.DNSNames certTemplate.EmailAddresses = csr.EmailAddresses certTemplate.IPAddresses = csr.IPAddresses certTemplate.ExtraExtensions = csr.Extensions } else { certTemplate.DNSNames = creationInfo.DNSNames certTemplate.EmailAddresses = creationInfo.EmailAddresses certTemplate.IPAddresses = creationInfo.IPAddresses } addKeyUsages(creationInfo, certTemplate) var certBytes []byte caCert := creationInfo.SigningBundle.Certificate certTemplate.IssuingCertificateURL = creationInfo.URLs.IssuingCertificates certTemplate.CRLDistributionPoints = creationInfo.URLs.CRLDistributionPoints certTemplate.OCSPServer = creationInfo.SigningBundle.URLs.OCSPServers if creationInfo.IsCA { certTemplate.BasicConstraintsValid = true certTemplate.IsCA = true if creationInfo.SigningBundle.Certificate.MaxPathLen == 0 && creationInfo.SigningBundle.Certificate.MaxPathLenZero { return nil, errutil.UserError{Err: "signing certificate has a max path length of zero, and cannot issue further CA certificates"} } certTemplate.MaxPathLen = creationInfo.MaxPathLength if certTemplate.MaxPathLen == 0 { certTemplate.MaxPathLenZero = true } } certBytes, err = x509.CreateCertificate(rand.Reader, certTemplate, caCert, csr.PublicKey, creationInfo.SigningBundle.PrivateKey) if err != nil { return nil, errutil.InternalError{Err: fmt.Sprintf("unable to create certificate: %s", err)} } result.CertificateBytes = certBytes result.Certificate, err = x509.ParseCertificate(certBytes) if err != nil { return nil, errutil.InternalError{Err: fmt.Sprintf("unable to parse created certificate: %s", err)} } result.IssuingCABytes = creationInfo.SigningBundle.CertificateBytes result.IssuingCA = creationInfo.SigningBundle.Certificate return result, nil }
func TestVerifyCSR(t *testing.T) { private, err := rsa.GenerateKey(rand.Reader, 2048) test.AssertNotError(t, err, "error generating test key") signedReqBytes, err := x509.CreateCertificateRequest(rand.Reader, &x509.CertificateRequest{PublicKey: private.PublicKey, SignatureAlgorithm: x509.SHA256WithRSA}, private) test.AssertNotError(t, err, "error generating test CSR") signedReq, err := x509.ParseCertificateRequest(signedReqBytes) test.AssertNotError(t, err, "error parsing test CSR") brokenSignedReq := new(x509.CertificateRequest) *brokenSignedReq = *signedReq brokenSignedReq.Signature = []byte{1, 1, 1, 1} signedReqWithHosts := new(x509.CertificateRequest) *signedReqWithHosts = *signedReq signedReqWithHosts.DNSNames = []string{"a.com", "b.com"} signedReqWithLongCN := new(x509.CertificateRequest) *signedReqWithLongCN = *signedReq signedReqWithLongCN.Subject.CommonName = strings.Repeat("a", maxCNLength+1) signedReqWithBadName := new(x509.CertificateRequest) *signedReqWithBadName = *signedReq signedReqWithBadName.DNSNames = []string{"bad-name.com"} cases := []struct { csr *x509.CertificateRequest maxNames int keyPolicy *goodkey.KeyPolicy pa core.PolicyAuthority regID int64 expectedError error }{ { &x509.CertificateRequest{}, 0, testingPolicy, &mockPA{}, 0, errors.New("invalid public key in CSR"), }, { &x509.CertificateRequest{PublicKey: private.PublicKey}, 1, testingPolicy, &mockPA{}, 0, errors.New("signature algorithm not supported"), }, { brokenSignedReq, 1, testingPolicy, &mockPA{}, 0, errors.New("invalid signature on CSR"), }, { signedReq, 1, testingPolicy, &mockPA{}, 0, errors.New("at least one DNS name is required"), }, { signedReqWithLongCN, 1, testingPolicy, &mockPA{}, 0, errors.New("CN was longer than 64 bytes"), }, { signedReqWithHosts, 1, testingPolicy, &mockPA{}, 0, errors.New("CSR contains more than 1 DNS names"), }, { signedReqWithBadName, 1, testingPolicy, &mockPA{}, 0, errors.New("policy forbids issuing for: bad-name.com"), }, } for _, c := range cases { err := VerifyCSR(c.csr, c.maxNames, c.keyPolicy, c.pa, false, c.regID) test.AssertDeepEquals(t, c.expectedError, err) } }
// Performs the heavy lifting of generating a certificate from a CSR. // Returns a ParsedCertBundle sans private keys. func signCertificate(creationInfo *creationBundle, csr *x509.CertificateRequest) (*certutil.ParsedCertBundle, error) { switch { case creationInfo == nil: return nil, certutil.UserError{Err: "nil creation info given to signCertificate"} case creationInfo.SigningBundle == nil: return nil, certutil.UserError{Err: "nil signing bundle given to signCertificate"} case csr == nil: return nil, certutil.UserError{Err: "nil csr given to signCertificate"} } err := csr.CheckSignature() if err != nil { return nil, certutil.UserError{Err: "request signature invalid"} } result := &certutil.ParsedCertBundle{} serialNumber, err := certutil.GenerateSerialNumber() if err != nil { return nil, err } marshaledKey, err := x509.MarshalPKIXPublicKey(csr.PublicKey) if err != nil { return nil, certutil.InternalError{Err: fmt.Sprintf("error marshalling public key: %s", err)} } subjKeyID := sha1.Sum(marshaledKey) subject := pkix.Name{ CommonName: creationInfo.CommonName, } certTemplate := &x509.Certificate{ SerialNumber: serialNumber, Subject: subject, NotBefore: time.Now(), NotAfter: time.Now().Add(creationInfo.TTL), SubjectKeyId: subjKeyID[:], } switch creationInfo.SigningBundle.PrivateKeyType { case certutil.RSAPrivateKey: certTemplate.SignatureAlgorithm = x509.SHA256WithRSA case certutil.ECPrivateKey: certTemplate.SignatureAlgorithm = x509.ECDSAWithSHA256 } if creationInfo.UseCSRValues { certTemplate.Subject = csr.Subject certTemplate.DNSNames = csr.DNSNames certTemplate.EmailAddresses = csr.EmailAddresses certTemplate.IPAddresses = csr.IPAddresses certTemplate.ExtraExtensions = csr.Extensions // Do not sign a CA certificate if they didn't go through the sign-intermediate // endpoint if !creationInfo.IsCA && oidInExtensions(oidExtensionBasicConstraints, certTemplate.ExtraExtensions) { return nil, certutil.UserError{Err: "will not sign a CSR asking for CA rights through this endpoint"} } } else { certTemplate.DNSNames = creationInfo.DNSNames certTemplate.EmailAddresses = creationInfo.EmailAddresses certTemplate.IPAddresses = creationInfo.IPAddresses certTemplate.KeyUsage = x509.KeyUsage(x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageKeyAgreement) if creationInfo.Usage&serverUsage != 0 { certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageServerAuth) } if creationInfo.Usage&clientUsage != 0 { certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageClientAuth) } if creationInfo.Usage&codeSigningUsage != 0 { certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageCodeSigning) } if creationInfo.Usage&emailProtectionUsage != 0 { certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageEmailProtection) } if creationInfo.IsCA { certTemplate.KeyUsage = x509.KeyUsage(certTemplate.KeyUsage | x509.KeyUsageCertSign | x509.KeyUsageCRLSign) certTemplate.ExtKeyUsage = append(certTemplate.ExtKeyUsage, x509.ExtKeyUsageOCSPSigning) } } var certBytes []byte caCert := creationInfo.SigningBundle.Certificate certTemplate.IssuingCertificateURL = creationInfo.URLs.IssuingCertificates certTemplate.CRLDistributionPoints = creationInfo.URLs.CRLDistributionPoints certTemplate.OCSPServer = creationInfo.SigningBundle.URLs.OCSPServers if creationInfo.IsCA { certTemplate.BasicConstraintsValid = true certTemplate.IsCA = true if creationInfo.SigningBundle.Certificate.MaxPathLen == 0 && creationInfo.SigningBundle.Certificate.MaxPathLenZero { return nil, certutil.UserError{Err: "signing certificate has a max path length of zero, and cannot issue further CA certificates"} } certTemplate.MaxPathLen = creationInfo.MaxPathLength if certTemplate.MaxPathLen == 0 { certTemplate.MaxPathLenZero = true } } certBytes, err = x509.CreateCertificate(rand.Reader, certTemplate, caCert, csr.PublicKey, creationInfo.SigningBundle.PrivateKey) if err != nil { return nil, certutil.InternalError{Err: fmt.Sprintf("unable to create certificate: %s", err)} } result.CertificateBytes = certBytes result.Certificate, err = x509.ParseCertificate(certBytes) if err != nil { return nil, certutil.InternalError{Err: fmt.Sprintf("unable to parse created certificate: %s", err)} } result.IssuingCABytes = creationInfo.SigningBundle.CertificateBytes result.IssuingCA = creationInfo.SigningBundle.Certificate return result, nil }