// NewSignerFromFile reads the issuer cert, the responder cert and the responder key // from PEM files, and takes an interval in seconds func NewSignerFromFile(issuerFile, responderFile, keyFile string, interval time.Duration) (Signer, error) { log.Debug("Loading issuer cert: ", issuerFile) issuerBytes, err := ioutil.ReadFile(issuerFile) if err != nil { return nil, err } log.Debug("Loading responder cert: ", responderFile) responderBytes, err := ioutil.ReadFile(responderFile) if err != nil { return nil, err } log.Debug("Loading responder key: ", keyFile) keyBytes, err := ioutil.ReadFile(keyFile) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ReadFailed, err) } issuerCert, err := helpers.ParseCertificatePEM(issuerBytes) if err != nil { return nil, err } responderCert, err := helpers.ParseCertificatePEM(responderBytes) if err != nil { return nil, err } key, err := helpers.ParsePrivateKeyPEM(keyBytes) if err != nil { log.Debug("Malformed private key %v", err) return nil, err } return NewSigner(issuerCert, responderCert, key, interval) }
func TestCAIssuing(t *testing.T) { var caCerts = []string{testCaFile, testECDSACaFile} var caKeys = []string{testCaKeyFile, testECDSACaKeyFile} var interCSRs = []string{ecdsaInterCSR, rsaInterCSR} var interKeys = []string{ecdsaInterKey, rsaInterKey} var CAPolicy = &config.Signing{ Default: &config.SigningProfile{ Usage: []string{"cert sign", "crl sign"}, ExpiryString: "1h", Expiry: 1 * time.Hour, CA: true, }, } var hostname = "cloudflare-inter.com" // Each RSA or ECDSA root CA issues two intermediate CAs (one ECDSA and one RSA). // For each intermediate CA, use it to issue additional RSA and ECDSA intermediate CSRs. for i, caFile := range caCerts { caKeyFile := caKeys[i] s := newCustomSigner(t, caFile, caKeyFile) s.policy = CAPolicy for j, csr := range interCSRs { csrBytes, _ := ioutil.ReadFile(csr) certBytes, err := s.Sign(signer.SignRequest{Hosts: signer.SplitHosts(hostname), Request: string(csrBytes)}) if err != nil { t.Fatal(err) } interCert, err := helpers.ParseCertificatePEM(certBytes) if err != nil { t.Fatal(err) } keyBytes, _ := ioutil.ReadFile(interKeys[j]) interKey, _ := helpers.ParsePrivateKeyPEM(keyBytes) interSigner := &Signer{interCert, interKey, CAPolicy, signer.DefaultSigAlgo(interKey)} for _, anotherCSR := range interCSRs { anotherCSRBytes, _ := ioutil.ReadFile(anotherCSR) bytes, err := interSigner.Sign( signer.SignRequest{ Hosts: signer.SplitHosts(hostname), Request: string(anotherCSRBytes), }) if err != nil { t.Fatal(err) } cert, err := helpers.ParseCertificatePEM(bytes) if err != nil { t.Fatal(err) } if cert.SignatureAlgorithm != interSigner.SigAlgo() { t.Fatal("Cert Signature Algorithm does not match the issuer.") } } } } }
func TestECDSASigner(t *testing.T) { s := newCustomSigner(t, testECDSACaFile, testECDSACaKeyFile) hostname := "cloudflare.com" for _, test := range csrTests { csr, err := ioutil.ReadFile(test.file) if err != nil { t.Fatal("CSR loading error:", err) } // Try all ECDSA SignatureAlgorithm SigAlgos := []x509.SignatureAlgorithm{x509.ECDSAWithSHA1, x509.ECDSAWithSHA256, x509.ECDSAWithSHA384, x509.ECDSAWithSHA512} for _, sigAlgo := range SigAlgos { s.sigAlgo = sigAlgo certBytes, err := s.Sign(signer.SignRequest{Hosts: signer.SplitHosts(hostname), Request: string(csr)}) if test.errorCallback != nil { test.errorCallback(t, err) } else { if err != nil { t.Fatalf("Expected no error. Got %s. Param %s %d", err.Error(), test.keyAlgo, test.keyLen) } cert, _ := helpers.ParseCertificatePEM(certBytes) if cert.SignatureAlgorithm != s.SigAlgo() { t.Fatal("Cert Signature Algorithm does not match the issuer.") } } } } }
func TestSignCSRs(t *testing.T) { s := newTestSigner(t) hostname := "cloudflare.com" for _, test := range csrTests { csr, err := ioutil.ReadFile(test.file) if err != nil { t.Fatal("CSR loading error:", err) } // It is possible to use different SHA2 algorithm with RSA CA key. rsaSigAlgos := []x509.SignatureAlgorithm{x509.SHA1WithRSA, x509.SHA256WithRSA, x509.SHA384WithRSA, x509.SHA512WithRSA} for _, sigAlgo := range rsaSigAlgos { s.sigAlgo = sigAlgo certBytes, err := s.Sign(signer.SignRequest{Hosts: signer.SplitHosts(hostname), Request: string(csr)}) if test.errorCallback != nil { test.errorCallback(t, err) } else { if err != nil { t.Fatalf("Expected no error. Got %s. Param %s %d", err.Error(), test.keyAlgo, test.keyLen) } cert, _ := helpers.ParseCertificatePEM(certBytes) if cert.SignatureAlgorithm != s.SigAlgo() { t.Fatal("Cert Signature Algorithm does not match the issuer.") } } } } }
// fetchRemoteCertificate retrieves a single URL pointing to a certificate // and attempts to first parse it as a DER-encoded certificate; if // this fails, it attempts to decode it as a PEM-encoded certificate. func fetchRemoteCertificate(certURL string) (fi *fetchedIntermediate, err error) { log.Debugf("fetching remote certificate: %s", certURL) var resp *http.Response resp, err = http.Get(certURL) if err != nil { log.Debugf("failed HTTP get: %v", err) return } defer resp.Body.Close() var certData []byte certData, err = ioutil.ReadAll(resp.Body) if err != nil { log.Debugf("failed to read response body: %v", err) return } log.Debugf("attempting to parse certificate as DER") crt, err := x509.ParseCertificate(certData) if err != nil { log.Debugf("attempting to parse certificate as PEM") crt, err = helpers.ParseCertificatePEM(certData) if err != nil { log.Debugf("failed to parse certificate: %v", err) return } } log.Debugf("certificate fetch succeeds") fi = &fetchedIntermediate{Cert: crt, Name: constructCertFileName(crt)} return }
func TestRemoteSignBadServerAndOverride(t *testing.T) { remoteServer := newTestSignServer(t) defer closeTestServer(t, remoteServer) // remoteConfig contains port 80 that no test server will listen on remoteConfig := newConfig(t, []byte(validMinimalRemoteConfig)) s := newRemoteSigner(t, remoteConfig.Signing) hosts := []string{"cloudflare.com"} csr, err := ioutil.ReadFile("../local/testdata/rsa2048.csr") if err != nil { t.Fatal("CSR loading error:", err) } _, err = s.Sign(signer.SignRequest{Hosts: hosts, Request: string(csr)}) if err == nil { t.Fatal("Should return error") } remoteConfig.Signing.OverrideRemotes(remoteServer.URL[7:]) s.SetPolicy(remoteConfig.Signing) certBytes, err := s.Sign(signer.SignRequest{Hosts: hosts, Request: string(csr)}) if err != nil { t.Fatalf("Expected no error. Got %s.", err.Error()) } _, err = helpers.ParseCertificatePEM(certBytes) if err != nil { t.Fatal("Fail to parse returned certificate:", err) } }
// NewSignerFromFile generates a new local signer from a caFile // and a caKey file, both PEM encoded. func NewSignerFromFile(caFile, caKeyFile string, policy *config.Signing) (*Signer, error) { log.Debug("Loading CA: ", caFile) ca, err := ioutil.ReadFile(caFile) if err != nil { return nil, err } log.Debug("Loading CA key: ", caKeyFile) cakey, err := ioutil.ReadFile(caKeyFile) if err != nil { return nil, cferr.Wrap(cferr.CertificateError, cferr.ReadFailed, err) } parsedCa, err := helpers.ParseCertificatePEM(ca) if err != nil { return nil, err } priv, err := helpers.ParsePrivateKeyPEM(cakey) if err != nil { log.Debug("Malformed private key %v", err) return nil, err } return NewSigner(priv, parsedCa, signer.DefaultSigAlgo(priv), policy) }
func TestOverrideSubject(t *testing.T) { csrPEM, err := ioutil.ReadFile(fullSubjectCSR) if err != nil { t.Fatalf("%v", err) } req := &signer.Subject{ Names: []csr.Name{ {O: "example.net"}, }, } s := newCustomSigner(t, testECDSACaFile, testECDSACaKeyFile) request := signer.SignRequest{ Hosts: []string{"127.0.0.1", "localhost"}, Request: string(csrPEM), Subject: req, } certPEM, err := s.Sign(request) if err != nil { t.Fatalf("%v", err) } cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatalf("%v", err) } block, _ := pem.Decode(csrPEM) template, err := x509.ParseCertificateRequest(block.Bytes) if err != nil { t.Fatal(err.Error()) } if cert.Subject.Organization[0] != "example.net" { t.Fatalf("Failed to override subject: want example.net but have %s", cert.Subject.Organization[0]) } if cert.Subject.Country[0] != template.Subject.Country[0] { t.Fatal("Failed to override Country") } if cert.Subject.Locality[0] != template.Subject.Locality[0] { t.Fatal("Failed to override Locality") } if cert.Subject.Organization[0] == template.Subject.Organization[0] { t.Fatal("Shouldn't have overrode Organization") } if cert.Subject.OrganizationalUnit[0] != template.Subject.OrganizationalUnit[0] { t.Fatal("Failed to override OrganizationalUnit") } log.Info("Overrode subject info") }
func TestNoWhitelistSign(t *testing.T) { csrPEM, err := ioutil.ReadFile(fullSubjectCSR) if err != nil { t.Fatalf("%v", err) } req := &signer.Subject{ Names: []csr.Name{ {O: "sam certificate authority"}, }, CN: "localhost", } s := newCustomSigner(t, testECDSACaFile, testECDSACaKeyFile) // No policy CSR whitelist: the normal set of CSR fields get passed through to // certificate. s.policy = &config.Signing{ Default: &config.SigningProfile{ Usage: []string{"cert sign", "crl sign"}, ExpiryString: "1h", Expiry: 1 * time.Hour, CA: true, }, } request := signer.SignRequest{ Hosts: []string{"127.0.0.1", "localhost"}, Request: string(csrPEM), Subject: req, } certPEM, err := s.Sign(request) if err != nil { t.Fatalf("%v", err) } cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatalf("%v", err) } name := cert.Subject if name.CommonName != "localhost" { t.Fatalf("Expected certificate common name to be 'localhost' but have '%v'", name.CommonName) } // CSR has: Subject: C=US, O=CloudFlare, OU=WWW, L=Ithaca, ST=New York // Expect all to be passed through. expectOneValueOf(t, name.Organization, "sam certificate authority", "O") expectOneValueOf(t, name.OrganizationalUnit, "WWW", "OU") expectOneValueOf(t, name.Province, "New York", "ST") expectOneValueOf(t, name.Locality, "Ithaca", "L") expectOneValueOf(t, name.Country, "US", "C") }
// Certificate returns the signer's certificate. func (s *Signer) Certificate(label, profile string) (*x509.Certificate, error) { certStr, err := s.Info(client.InfoReq{Label: label, Profile: profile}) if err != nil { return nil, err } cert, err := helpers.ParseCertificatePEM(certStr) if err != nil { return nil, err } return cert, nil }
func TestSign(t *testing.T) { dur, _ := time.ParseDuration("1ms") // expected case s, err := NewSignerFromFile(serverCertFile, otherCertFile, serverKeyFile, dur) if err != nil { t.Fatalf("Signer creation failed: %v", err) } _, err = s.Sign(SignRequest{}) if err == nil { t.Fatal("Signed request with nil certificate") } certPEM, err := ioutil.ReadFile(otherCertFile) if err != nil { t.Fatal(err) } cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatal(err) } req := SignRequest{ Certificate: cert, Status: "good", } _, err = s.Sign(req) if err != nil { t.Fatal("Sign failed") } sMismatch, err := NewSignerFromFile(wrongServerCertFile, otherCertFile, wrongServerKeyFile, dur) _, err = sMismatch.Sign(req) if err == nil { t.Fatal("Signed a certificate from the wrong issuer") } // incorrect status code req.Status = "aalkjsfdlkafdslkjahds" _, err = s.Sign(req) if err == nil { t.Fatal("Failed to fail on improper status code") } // revoked req.Status = "revoked" _, err = s.Sign(req) if err != nil { t.Fatal("Error on revoked certificate") } }
func loadIssuer(filename string) (issuerCert *x509.Certificate, err error) { if filename == "" { err = errors.New("Issuer certificate was not provided in config.") return } issuerCertPEM, err := ioutil.ReadFile(filename) if err != nil { return } issuerCert, err = helpers.ParseCertificatePEM(issuerCertPEM) return }
// ocspSignerMain is the main CLI of OCSP signer functionality. func ocspSignerMain(args []string, c cli.Config) (err error) { // Read the cert to be revoked from file certBytes, err := ioutil.ReadFile(c.CertFile) if err != nil { log.Critical("Unable to read certificate: ", err) return } cert, err := helpers.ParseCertificatePEM(certBytes) if err != nil { log.Critical("Unable to parse certificate: ", err) return } req := ocsp.SignRequest{ Certificate: cert, Status: c.Status, } if c.Status == "revoked" { req.Reason = c.Reason req.RevokedAt = time.Now() if c.RevokedAt != "now" { req.RevokedAt, err = time.Parse("2006-01-02", c.RevokedAt) if err != nil { log.Critical("Malformed revocation time: ", c.RevokedAt) return } } } s, err := ocsp.NewSignerFromFile(c.CAFile, c.ResponderFile, c.KeyFile, time.Duration(c.Interval)) if err != nil { log.Critical("Unable to create OCSP signer: ", err) return } resp, err := s.Sign(req) if err != nil { log.Critical("Unable to sign OCSP response: ", err) return } cli.PrintOCSPResponse(resp) return }
func TestMain(m *testing.M) { caKeyPEM, _ := ioutil.ReadFile(caKeyFile) caKey, _ := helpers.ParsePrivateKeyPEM(caKeyPEM) caCertPEM, _ := ioutil.ReadFile(caCertFile) caCert, _ := helpers.ParseCertificatePEM(caCertPEM) // Create an online CFSSL instance // This is designed to mimic what LE plans to do authHandler, _ := auth.New(authKey, nil) policy := &cfsslConfig.Signing{ Profiles: map[string]*cfsslConfig.SigningProfile{ profileName: &cfsslConfig.SigningProfile{ Usage: []string{"server auth"}, CA: false, IssuerURL: []string{"http://not-example.com/issuer-url"}, OCSP: "http://not-example.com/ocsp", CRL: "http://not-example.com/crl", Policies: []asn1.ObjectIdentifier{ asn1.ObjectIdentifier{2, 23, 140, 1, 2, 1}, }, Expiry: 8760 * time.Hour, Backdate: time.Hour, Provider: authHandler, CSRWhitelist: &cfsslConfig.CSRWhitelist{ PublicKeyAlgorithm: true, PublicKey: true, SignatureAlgorithm: true, }, }, }, Default: &cfsslConfig.SigningProfile{ Expiry: time.Hour, }, } cfsslSigner, _ = local.NewSigner(caKey, caCert, x509.SHA256WithRSA, policy) signHandler, _ := apisign.NewAuthHandlerFromSigner(cfsslSigner) http.Handle("/api/v1/cfssl/authsign", signHandler) // This goroutine should get killed when main() return go (func() { http.ListenAndServe(hostPort, nil) })() os.Exit(m.Run()) }
// New returns a new PKCS #11 signer. func NewPKCS11Signer(cfg ocspConfig.Config) (ocsp.Signer, error) { log.Debugf("Loading PKCS #11 module %s", cfg.PKCS11.Module) certData, err := ioutil.ReadFile(cfg.CACertFile) if err != nil { return nil, errors.New(errors.CertificateError, errors.ReadFailed) } cert, err := helpers.ParseCertificatePEM(certData) if err != nil { return nil, err } PKCS11 := cfg.PKCS11 priv, err := pkcs11key.New(PKCS11.Module, PKCS11.Token, PKCS11.PIN, PKCS11.Label) if err != nil { return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed) } return ocsp.NewSigner(cert, cert, priv, cfg.Interval) }
func TestRemoteSign(t *testing.T) { remoteServer := newTestSignServer(t) defer closeTestServer(t, remoteServer) remoteConfig := newConfig(t, []byte(validMinimalRemoteConfig)) // override with test server address, ignore url prefix "http://" remoteConfig.Signing.OverrideRemotes(remoteServer.URL[7:]) s := newRemoteSigner(t, remoteConfig.Signing) hosts := []string{"cloudflare.com"} for _, test := range csrTests { csr, err := ioutil.ReadFile(test.file) if err != nil { t.Fatal("CSR loading error:", err) } testSeq := "7007F" certBytes, err := s.Sign(signer.SignRequest{Hosts: hosts, Request: string(csr), SerialSeq: testSeq}) if test.errorCallback != nil { test.errorCallback(t, err) } else { if err != nil { t.Fatalf("Expected no error. Got %s. Param %s %d", err.Error(), test.keyAlgo, test.keyLen) } cert, err := helpers.ParseCertificatePEM(certBytes) if err != nil { t.Fatal("Fail to parse returned certificate:", err) } sn := fmt.Sprintf("%X", cert.SerialNumber) if sn[0:len(testSeq)] != testSeq { t.Fatal("Serial Number did not begin with seq:", sn) } if len(sn) != len(testSeq)+16 { t.Fatal("Serial Number unexpected length:", sn) } } } }
// New returns a new PKCS #11 signer. func New(caCertFile string, policy *config.Signing, cfg *pkcs11key.Config) (signer.Signer, error) { if cfg == nil { return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed) } log.Debugf("Loading PKCS #11 module %s", cfg.Module) certData, err := ioutil.ReadFile(caCertFile) if err != nil { return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed) } cert, err := helpers.ParseCertificatePEM(certData) if err != nil { return nil, err } priv, err := pkcs11key.New(cfg.Module, cfg.TokenLabel, cfg.PIN, cfg.PrivateKeyLabel) if err != nil { return nil, errors.New(errors.PrivateKeyError, errors.ReadFailed) } sigAlgo := signer.DefaultSigAlgo(priv) return local.NewSigner(priv, cert, sigAlgo, policy) }
// test the private method func testSign(t *testing.T) { signer, err := NewSignerFromFile("testdata/ca.pem", "testdata/ca_key.pem", nil) if signer == nil || err != nil { t.Fatal("Failed to produce signer") } pem, _ := ioutil.ReadFile("../../helpers/testdata/cert.pem") cert, _ := helpers.ParseCertificatePEM(pem) badcert := *cert badcert.PublicKey = nil profl := config.SigningProfile{Usage: []string{"Certificates", "Rule"}} _, err = signer.sign(&badcert, &profl, "") if err == nil { t.Fatal("Improper input failed to raise an error") } // nil profile _, err = signer.sign(cert, &profl, "") if err == nil { t.Fatal("Nil profile failed to raise an error") } // empty profile _, err = signer.sign(cert, &config.SigningProfile{}, "") if err == nil { t.Fatal("Empty profile failed to raise an error") } // empty expiry prof := signer.policy.Default prof.Expiry = 0 _, err = signer.sign(cert, prof, "") if err != nil { t.Fatal("nil expiry raised an error") } // non empty urls prof = signer.policy.Default prof.CRL = "stuff" prof.OCSP = "stuff" prof.IssuerURL = []string{"stuff"} _, err = signer.sign(cert, prof, "") if err != nil { t.Fatal("non nil urls raised an error") } // nil ca nilca := *signer prof = signer.policy.Default prof.CA = false nilca.ca = nil _, err = nilca.sign(cert, prof, "") if err == nil { t.Fatal("nil ca with isca false raised an error") } prof.CA = true _, err = nilca.sign(cert, prof, "") if err != nil { t.Fatal("nil ca with CA true raised an error") } }
func TestOverwriteHosts(t *testing.T) { for _, csrFile := range []string{testCSR, testSANCSR} { csrPEM, err := ioutil.ReadFile(csrFile) if err != nil { t.Fatal(err) } csrDER, _ := pem.Decode([]byte(csrPEM)) if err != nil { t.Fatal(err) } csr, err := x509.ParseCertificateRequest(csrDER.Bytes) if err != nil { t.Fatal(err) } csrHosts := csr.DNSNames for _, ip := range csr.IPAddresses { csrHosts = append(csrHosts, ip.String()) } sort.Strings(csrHosts) s := newCustomSigner(t, testECDSACaFile, testECDSACaKeyFile) for _, hosts := range [][]string{ nil, []string{}, []string{"127.0.0.1", "localhost"}, } { request := signer.SignRequest{ Hosts: hosts, Request: string(csrPEM), Subject: nil, } certPEM, err := s.Sign(request) if err != nil { t.Fatalf("%v", err) } cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatalf("%v", err) } // get the hosts, and add the ips certHosts := cert.DNSNames for _, ip := range cert.IPAddresses { certHosts = append(certHosts, ip.String()) } // compare the sorted host lists sort.Strings(certHosts) sort.Strings(request.Hosts) if len(request.Hosts) > 0 && !reflect.DeepEqual(certHosts, request.Hosts) { t.Fatalf("Hosts not the same. cert hosts: %v, expected: %v", certHosts, request.Hosts) } if request.Hosts == nil && !reflect.DeepEqual(certHosts, csrHosts) { t.Fatalf("Hosts not the same. cert hosts: %v, expected csr hosts: %v", certHosts, csrHosts) } if request.Hosts != nil && len(request.Hosts) == 0 && len(certHosts) != 0 { t.Fatalf("Hosts not the same. cert hosts: %v, expected: %v", certHosts, request.Hosts) } } } }
func TestWhitelistSign(t *testing.T) { csrPEM, err := ioutil.ReadFile(fullSubjectCSR) if err != nil { t.Fatalf("%v", err) } req := &signer.Subject{ Names: []csr.Name{ {O: "sam certificate authority"}, }, } s := newCustomSigner(t, testECDSACaFile, testECDSACaKeyFile) // Whitelist only key-related fields. Subject, DNSNames, etc shouldn't get // passed through from CSR. s.policy = &config.Signing{ Default: &config.SigningProfile{ Usage: []string{"cert sign", "crl sign"}, ExpiryString: "1h", Expiry: 1 * time.Hour, CA: true, CSRWhitelist: &config.CSRWhitelist{ PublicKey: true, PublicKeyAlgorithm: true, SignatureAlgorithm: true, }, }, } request := signer.SignRequest{ Hosts: []string{"127.0.0.1", "localhost"}, Request: string(csrPEM), Subject: req, } certPEM, err := s.Sign(request) if err != nil { t.Fatalf("%v", err) } cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatalf("%v", err) } name := cert.Subject if name.CommonName != "" { t.Fatalf("Expected empty certificate common name under policy without "+ "Subject whitelist, got %v", name.CommonName) } // O is provided by the signing API request, not the CSR, so it's allowed to // be copied into the certificate. expectOneValueOf(t, name.Organization, "sam certificate authority", "O") expectEmpty(t, name.OrganizationalUnit, "OU") expectEmpty(t, name.Province, "ST") expectEmpty(t, name.Locality, "L") expectEmpty(t, name.Country, "C") if cert.PublicKeyAlgorithm != x509.RSA { t.Fatalf("Expected public key algorithm to be RSA") } // Signature algorithm is allowed to be copied from CSR, but is overridden by // DefaultSigAlgo. if cert.SignatureAlgorithm != x509.ECDSAWithSHA256 { t.Fatalf("Expected public key algorithm to be ECDSAWithSHA256, got %v", cert.SignatureAlgorithm) } }
// readCert read a PEM file and returns a cert. func readCert(filename string) *x509.Certificate { bytes, _ := ioutil.ReadFile(filename) cert, _ := helpers.ParseCertificatePEM(bytes) return cert }
func TestInitCA(t *testing.T) { var req *csr.CertificateRequest hostname := "cloudflare.com" for _, param := range validKeyParams { req = &csr.CertificateRequest{ Names: []csr.Name{ { C: "US", ST: "California", L: "San Francisco", O: "CloudFlare", OU: "Systems Engineering", }, }, CN: hostname, Hosts: []string{hostname, "www." + hostname}, KeyRequest: &csr.KeyRequest{ Algo: param.keyAlgo, Size: param.keyLen, }, } certBytes, keyBytes, err := New(req) if err != nil { t.Fatal("InitCA failed:", err) } key, err := helpers.ParsePrivateKeyPEM(keyBytes) if err != nil { t.Fatal("InitCA private key parsing failed:", err) } cert, err := helpers.ParseCertificatePEM(certBytes) if err != nil { t.Fatal("InitCA cert parsing failed:", err) } // Verify key parameters. switch req.KeyRequest.Algo { case "rsa": if cert.PublicKey.(*rsa.PublicKey).N.BitLen() != param.keyLen { t.Fatal("Cert key length mismatch.") } if key.(*rsa.PrivateKey).N.BitLen() != param.keyLen { t.Fatal("Private key length mismatch.") } case "ecdsa": if cert.PublicKey.(*ecdsa.PublicKey).Curve.Params().BitSize != param.keyLen { t.Fatal("Cert key length mismatch.") } if key.(*ecdsa.PrivateKey).Curve.Params().BitSize != param.keyLen { t.Fatal("Private key length mismatch.") } } // Start a signer var CAPolicy = &config.Signing{ Default: &config.SigningProfile{ Usage: []string{"cert sign", "crl sign"}, ExpiryString: "300s", Expiry: 300 * time.Second, CA: true, }, } s, err := local.NewSigner(key, cert, signer.DefaultSigAlgo(key), nil) if err != nil { t.Fatal("Signer Creation error:", err) } s.SetPolicy(CAPolicy) // Sign RSA and ECDSA customer CSRs. for _, csrFile := range csrFiles { csrBytes, err := ioutil.ReadFile(csrFile) if err != nil { t.Fatal("CSR loading error:", err) } req := signer.SignRequest{ Request: string(csrBytes), Hosts: signer.SplitHosts(hostname), Profile: "", Label: "", } bytes, err := s.Sign(req) if err != nil { t.Fatal(err) } customerCert, _ := helpers.ParseCertificatePEM(bytes) if customerCert.SignatureAlgorithm != s.SigAlgo() { t.Fatal("Signature Algorithm mismatch") } err = customerCert.CheckSignatureFrom(cert) if err != nil { t.Fatal("Signing CSR failed.", err) } } } }