// 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) }
// 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) }
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) }
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) }
// 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 }
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) } }