func TestSign(t *testing.T) { signer := newTestSigner(t) clientCertPEM, err := ioutil.ReadFile(testClientCertFile) if err != nil { t.Fatal(err) } clientCert, err := helpers.ParseCertificatePEM(clientCertPEM) if err != nil { t.Fatal(err) } certPEM, err := signer.Sign(testHostName, clientCertPEM, "") if err != nil { t.Fatal(err) } cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatal(err) } if err := cert.CheckSignatureFrom(signer.CA); err != nil { t.Fatal(err) } if err := cert.VerifyHostname(testHostName); err != nil { t.Fatal(err) } if !reflect.DeepEqual(cert.PublicKey, clientCert.PublicKey) { t.Fatal("Cert public key does not match clientCert", cert.PublicKey, clientCert.PublicKey) } }
// 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{ ca: interCert, priv: interKey, policy: CAPolicy, sigAlgo: 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 verifyRemoteSign(t *testing.T, remoteConfig *config.Config) { s := newRemoteSigner(t, remoteConfig.Signing) hosts := []string{"cloudflare.com"} for _, test := range testsuite.CSRTests { csr, err := ioutil.ReadFile(test.File) if err != nil { t.Fatal("CSR loading error:", err) } testSerial := big.NewInt(0x7007F) certBytes, err := s.Sign(signer.SignRequest{ Hosts: hosts, Request: string(csr), Serial: testSerial, }) 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 != "7007F" { t.Fatal("Serial Number was incorrect:", sn) } } } }
// 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 }
// GetRemoteCA returns the remote endpoint's CA certificate func GetRemoteCA(ctx context.Context, d digest.Digest, picker *picker.Picker) (RootCA, error) { // We need a valid picker to be able to Dial to a remote CA if picker == nil { return RootCA{}, fmt.Errorf("valid remote address picker required") } // This TLS Config is intentionally using InsecureSkipVerify. Either we're // doing TOFU, in which case we don't validate the remote CA, or we're using // a user supplied hash to check the integrity of the CA certificate. insecureCreds := credentials.NewTLS(&tls.Config{InsecureSkipVerify: true}) opts := []grpc.DialOption{ grpc.WithTransportCredentials(insecureCreds), grpc.WithBackoffMaxDelay(10 * time.Second), grpc.WithPicker(picker)} firstAddr, err := picker.PickAddr() if err != nil { return RootCA{}, err } conn, err := grpc.Dial(firstAddr, opts...) if err != nil { return RootCA{}, err } defer conn.Close() client := api.NewCAClient(conn) response, err := client.GetRootCACertificate(ctx, &api.GetRootCACertificateRequest{}) if err != nil { return RootCA{}, err } if d != "" { verifier, err := digest.NewDigestVerifier(d) if err != nil { return RootCA{}, fmt.Errorf("unexpected error getting digest verifier: %v", err) } io.Copy(verifier, bytes.NewReader(response.Certificate)) if !verifier.Verified() { return RootCA{}, fmt.Errorf("remote CA does not match fingerprint. Expected: %s", d.Hex()) } } // Check the validity of the remote Cert _, err = helpers.ParseCertificatePEM(response.Certificate) if err != nil { return RootCA{}, err } // Create a Pool with our RootCACertificate pool := x509.NewCertPool() if !pool.AppendCertsFromPEM(response.Certificate) { return RootCA{}, fmt.Errorf("failed to append certificate to cert pool") } return RootCA{Cert: response.Certificate, Pool: pool}, nil }
func getInfoFromRemote(c cli.Config) (resp *info.Resp, err error) { req := new(info.Req) req.Label = c.Label req.Profile = c.Profile cert, err := helpers.LoadClientCertificate(c.MutualTLSCertFile, c.MutualTLSKeyFile) if err != nil { return } remoteCAs, err := helpers.LoadPEMCertPool(c.TLSRemoteCAs) if err != nil { return } serv := client.NewServerTLS(c.Remote, helpers.CreateTLSConfig(remoteCAs, cert)) reqJSON, _ := json.Marshal(req) resp, err = serv.Info(reqJSON) if err != nil { return } _, err = helpers.ParseCertificatePEM([]byte(resp.Certificate)) if err != nil { return } return }
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.") } } } } }
// 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 } strPassword := os.Getenv("CFSSL_CA_PK_PASSWORD") password := []byte(strPassword) if strPassword == "" { password = nil } priv, err := helpers.ParsePrivateKeyPEMWithPassword(cakey, password) if err != nil { log.Debug("Malformed private key %v", err) return nil, err } return NewSigner(priv, parsedCa, signer.DefaultSigAlgo(priv), policy) }
// 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 TestExtractCertificateRequest(t *testing.T) { certPEM, err := ioutil.ReadFile(testECDSACertificateFile) if err != nil { t.Fatal(err) } // must parse ok cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { t.Fatal(err) } req := ExtractCertificateRequest(cert) if req.CN != "" { t.Fatal("Bad Certificate Request!") } if len(req.Names) != 1 { t.Fatal("Bad Certificate Request!") } name := req.Names[0] if name.C != "US" || name.ST != "California" || name.O != "CloudFlare, Inc." || name.OU != "Test Certificate Authority" || name.L != "San Francisco" { t.Fatal("Bad Certificate Request!") } if req.CA == nil || req.CA.PathLength != 2 { t.Fatal("Bad Certificate Request!") } }
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) } }
// GetSKICertPEM returns the SKI of a PEM encoded X.509 Certificate func GetSKICertPEM(certPEM []byte) (SKI, error) { cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { return nilSKI, err } return GetSKICert(cert) }
func makeCASigner(certBytes, keyBytes []byte, sigAlgo x509.SignatureAlgorithm, t *testing.T) signer.Signer { cert, err := helpers.ParseCertificatePEM(certBytes) if err != nil { t.Fatal(err) } key, err := helpers.ParsePrivateKeyPEM(keyBytes) if err != nil { t.Fatal(err) } defaultProfile := &config.SigningProfile{ Usage: []string{"cert sign"}, CAConstraint: config.CAConstraint{IsCA: true}, Expiry: time.Hour, ExpiryString: "1h", } policy := &config.Signing{ Profiles: map[string]*config.SigningProfile{}, Default: defaultProfile, } s, err := local.NewSigner(key, cert, sigAlgo, policy) if err != nil { t.Fatal(err) } return s }
func NewCFSSLSigner(caFile, caKeyFile string) (*CFSSLSigner, error) { ca, err := ioutil.ReadFile(caFile) if err != nil { return nil, err } cakey, err := ioutil.ReadFile(caKeyFile) if err != nil { return nil, err } parsedCa, err := helpers.ParseCertificatePEM(ca) if err != nil { return nil, err } strPassword := os.Getenv("CFSSL_CA_PK_PASSWORD") password := []byte(strPassword) if strPassword == "" { password = nil } priv, err := helpers.ParsePrivateKeyPEMWithPassword(cakey, password) if err != nil { return nil, fmt.Errorf("Malformed private key %v", err) } return &CFSSLSigner{ priv: priv, ca: parsedCa, sigAlgo: signer.DefaultSigAlgo(priv), }, nil }
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.") } } } } }
// ParseCertificatePEM parses an x509 certificate PEM. func ParseCertificatePEM(certPEM []byte) (*Certificate, error) { cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { return nil, err } return ParseCertificate(cert), nil }
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") }
// LoadRoot parses a config structure into a Root structure func LoadRoot(cfg map[string]string) (*Root, error) { var root Root var err error spec, ok := cfg["private"] if !ok { return nil, ErrMissingPrivateKey } certPath, ok := cfg["certificate"] if !ok { return nil, ErrMissingCertificatePath } configPath, ok := cfg["config"] if !ok { return nil, ErrMissingConfigPath } root.PrivateKey, err = parsePrivateKeySpec(spec, cfg) if err != nil { return nil, err } in, err := ioutil.ReadFile(certPath) if err != nil { return nil, err } root.Certificate, err = helpers.ParseCertificatePEM(in) if err != nil { return nil, err } conf, err := config.LoadFile(configPath) if err != nil { return nil, err } root.Config = conf.Signing nets := cfg["nets"] if nets != "" { root.ACL, err = parseACL(nets) if err != nil { return nil, err } } dbConfig := cfg["dbconfig"] if dbConfig != "" { db, err := certdb.DBFromConfig(dbConfig) if err != nil { return nil, err } root.DB = db } return &root, nil }
// Handle responds to requests for a ocsp signature. It creates and signs // a ocsp response for the provided certificate and status. If the status // is revoked then it also adds reason and revoked_at. The response is // base64 encoded. func (h *Handler) Handle(w http.ResponseWriter, r *http.Request) error { body, err := ioutil.ReadAll(r.Body) if err != nil { return err } r.Body.Close() // Default the status to good so it matches the cli req := &jsonSignRequest{ Status: "good", } err = json.Unmarshal(body, req) if err != nil { return errors.NewBadRequestString("Unable to parse sign request") } cert, err := helpers.ParseCertificatePEM([]byte(req.Certificate)) if err != nil { log.Error("Error from ParseCertificatePEM", err) return errors.NewBadRequestString("Malformed certificate") } signReq := ocsp.SignRequest{ Certificate: cert, Status: req.Status, } // We need to convert the time from being a string to a time.Time if req.Status == "revoked" { signReq.Reason = req.Reason // "now" is accepted and the default on the cli so default that here if req.RevokedAt == "" || req.RevokedAt == "now" { signReq.RevokedAt = time.Now() } else { signReq.RevokedAt, err = time.Parse("2006-01-02", req.RevokedAt) if err != nil { return errors.NewBadRequestString("Malformed revocation time") } } } if req.IssuerHash != "" { issuerHash, ok := nameToHash[req.IssuerHash] if !ok { return errors.NewBadRequestString("Unsupported hash algorithm in request") } signReq.IssuerHash = issuerHash } resp, err := h.signer.Sign(signReq) if err != nil { return err } b64Resp := base64.StdEncoding.EncodeToString(resp) result := map[string]string{"ocspResponse": b64Resp} return api.SendResponse(w, result) }
// createAndWriteca.RootCA creates a Certificate authority for a new Swarm Cluster. // We're copying CreateAndWriteca.RootCA, so we can have smaller key-sizes for tests func createAndWriteRootCA(rootCN string, paths ca.CertPaths, expiry time.Duration) (ca.RootCA, error) { // Create a simple CSR for the CA using the default CA validator and policy req := cfcsr.CertificateRequest{ CN: rootCN, KeyRequest: cfcsr.NewBasicKeyRequest(), CA: &cfcsr.CAConfig{Expiry: ca.RootCAExpiration}, } // Generate the CA and get the certificate and private key cert, _, key, err := initca.New(&req) if err != nil { return ca.RootCA{}, err } // Convert the key given by initca to an object to create a ca.RootCA parsedKey, err := helpers.ParsePrivateKeyPEM(key) if err != nil { log.Errorf("failed to parse private key: %v", err) return ca.RootCA{}, err } // Convert the certificate into an object to create a ca.RootCA parsedCert, err := helpers.ParseCertificatePEM(cert) if err != nil { return ca.RootCA{}, err } // Create a Signer out of the private key signer, err := local.NewSigner(parsedKey, parsedCert, cfsigner.DefaultSigAlgo(parsedKey), ca.SigningPolicy(expiry)) if err != nil { log.Errorf("failed to create signer: %v", err) return ca.RootCA{}, err } // Ensure directory exists err = os.MkdirAll(filepath.Dir(paths.Cert), 0755) if err != nil { return ca.RootCA{}, err } // Write the Private Key and Certificate to disk, using decent permissions if err := ioutils.AtomicWriteFile(paths.Cert, cert, 0644); err != nil { return ca.RootCA{}, err } if err := ioutils.AtomicWriteFile(paths.Key, key, 0600); err != nil { return ca.RootCA{}, err } // Create a Pool with our Root CA Certificate pool := x509.NewCertPool() if !pool.AppendCertsFromPEM(cert) { return ca.RootCA{}, fmt.Errorf("failed to append certificate to cert pool") } return ca.RootCA{Signer: signer, Key: key, Cert: cert, Pool: pool}, nil }
// SetCertificatePEM receives a PEM-encoded certificate and loads it // into the provider. func (sp *StandardProvider) SetCertificatePEM(certPEM []byte) error { cert, err := helpers.ParseCertificatePEM(certPEM) if err != nil { return errors.New("transport: invalid certificate") } sp.internal.certPEM = certPEM sp.internal.cert = cert return nil }
func TestUniversalRemoteAndLocalSign(t *testing.T) { // set up remote server remoteConfig := testsuite.NewConfig(t, []byte(validNoAuthRemoteConfig)) remoteServer := newTestSignServer(t, newTestUniversalSigner(t, remoteConfig.Signing)) defer closeTestServer(t, remoteServer) universalConfig := testsuite.NewConfig(t, []byte(validNoAuthUniversalConfig)) // override with test server address, ignore url prefix "http://" for name, profile := range universalConfig.Signing.Profiles { if profile.RemoteServer != "" { universalConfig.Signing.Profiles[name].RemoteServer = remoteServer.URL[7:] } } s := newTestUniversalSigner(t, universalConfig.Signing) checkSign := func(name string, profile *config.SigningProfile) { hosts := []string{"cloudflare.com"} for _, test := range testsuite.CSRTests { csr, err := ioutil.ReadFile(test.File) if err != nil { t.Fatalf("CSR loading error (%s): %v", name, err) } testSerial := big.NewInt(0x7007F) certBytes, err := s.Sign(signer.SignRequest{ Hosts: hosts, Request: string(csr), Serial: testSerial, Profile: name, }) 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) } ku, _, _ := profile.Usages() if cert.KeyUsage != ku { t.Fatalf("Key usage was incorrect expected %+v, got %+v", ku, cert.KeyUsage) } } } } for name, profile := range universalConfig.Signing.Profiles { checkSign(name, profile) } // add check for default profile checkSign("", universalConfig.Signing.Default) }
// NewCRLFromFile takes in a list of serial numbers, one per line, as well as the issuing certificate // of the CRL, and the private key. This function is then used to parse the list and generate a CRL func NewCRLFromFile(serialList, issuerFile, keyFile []byte, expiryTime string) ([]byte, error) { var revokedCerts []pkix.RevokedCertificate var oneWeek = time.Duration(604800) * time.Second expiryInt, err := strconv.ParseInt(expiryTime, 0, 32) if err != nil { return nil, err } newDurationFromInt := time.Duration(expiryInt) * time.Second newExpiryTime := time.Now().Add(newDurationFromInt) if expiryInt == 0 { newExpiryTime = time.Now().Add(oneWeek) } // Parse the PEM encoded certificate issuerCert, err := helpers.ParseCertificatePEM(issuerFile) if err != nil { return nil, err } // Split input file by new lines individualCerts := strings.Split(string(serialList), "\n") // For every new line, create a new revokedCertificate and add it to slice for _, value := range individualCerts { if len(strings.TrimSpace(value)) == 0 { continue } tempBigInt := new(big.Int) tempBigInt.SetString(value, 10) tempCert := pkix.RevokedCertificate{ SerialNumber: tempBigInt, RevocationTime: time.Now(), } revokedCerts = append(revokedCerts, tempCert) } strPassword := os.Getenv("CFSSL_CA_PK_PASSWORD") password := []byte(strPassword) if strPassword == "" { password = nil } // Parse the key given key, err := helpers.ParsePrivateKeyPEMWithPassword(keyFile, password) if err != nil { log.Debug("Malformed private key %v", err) return nil, err } return CreateGenericCRL(revokedCerts, key, issuerCert, newExpiryTime) }
// createAndWriteRootCA creates a Certificate authority for a new Swarm Cluster. // We're copying ca.CreateRootCA, so we can have smaller key-sizes for tests func createAndWriteRootCA(rootCN string, paths ca.CertPaths, expiry time.Duration) (ca.RootCA, error) { cert, key, err := CreateRootCertAndKey(rootCN) if err != nil { return ca.RootCA{}, err } // Convert the key given by initca to an object to create a ca.RootCA parsedKey, err := helpers.ParsePrivateKeyPEM(key) if err != nil { log.Errorf("failed to parse private key: %v", err) return ca.RootCA{}, err } // Convert the certificate into an object to create a ca.RootCA parsedCert, err := helpers.ParseCertificatePEM(cert) if err != nil { return ca.RootCA{}, err } // Create a Signer out of the private key signer, err := local.NewSigner(parsedKey, parsedCert, cfsigner.DefaultSigAlgo(parsedKey), ca.SigningPolicy(expiry)) if err != nil { log.Errorf("failed to create signer: %v", err) return ca.RootCA{}, err } // Ensure directory exists err = os.MkdirAll(filepath.Dir(paths.Cert), 0755) if err != nil { return ca.RootCA{}, err } // Write the Private Key and Certificate to disk, using decent permissions if err := ioutils.AtomicWriteFile(paths.Cert, cert, 0644); err != nil { return ca.RootCA{}, err } if err := ioutils.AtomicWriteFile(paths.Key, key, 0600); err != nil { return ca.RootCA{}, err } // Create a Pool with our Root CA Certificate pool := x509.NewCertPool() if !pool.AppendCertsFromPEM(cert) { return ca.RootCA{}, errors.New("failed to append certificate to cert pool") } return ca.RootCA{ Signer: signer, Key: key, Cert: cert, Pool: pool, Digest: digest.FromBytes(cert), }, nil }
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") }
func TestNewSigner(t *testing.T) { req := ExampleRequest() lca, err := New(req, ExampleSigningConfig()) assert.NoErrorT(t, err) csrPEM, _, err := csr.ParseRequest(testRequest) assert.NoErrorT(t, err) certPEM, err := lca.SignCSR(csrPEM) assert.NoErrorT(t, err) _, err = helpers.ParseCertificatePEM(certPEM) assert.NoErrorT(t, err) certPEM, err = lca.CACertificate() assert.NoErrorT(t, err) cert, err := helpers.ParseCertificatePEM(certPEM) assert.NoErrorT(t, err) assert.BoolT(t, cert.Subject.CommonName == req.CN, "common names don't match") lca.Toggle() _, err = lca.SignCSR(csrPEM) assert.ErrorEqT(t, errDisabled, err) lca.Toggle() _, err = lca.SignCSR(certPEM) assert.ErrorT(t, err, "shouldn't be able to sign non-CSRs") p := &pem.Block{ Type: "CERTIFICATE REQUEST", Bytes: []byte(`¯\_(ツ)_/¯`), } junkCSR := pem.EncodeToMemory(p) _, err = lca.SignCSR(junkCSR) assert.ErrorT(t, err, "signing a junk CSR should fail") t.Logf("error: %s", err) }
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") } }
// Parse loads a RootList from a file. func Parse(filename string) (RootList, error) { cfgMap, err := parseFile(filename) if err != nil { return nil, err } var rootList = RootList{} for label, entries := range cfgMap { var root Root spec, ok := entries["private"] if !ok { return nil, ErrMissingPrivateKey } certPath, ok := entries["certificate"] if !ok { return nil, ErrMissingCertificatePath } configPath, ok := entries["config"] if !ok { return nil, ErrMissingConfigPath } // Entries is provided for any additional // configuration data that may need to come from the // section. root.PrivateKey, err = parsePrivateKeySpec(spec, entries) if err != nil { return nil, err } in, err := ioutil.ReadFile(certPath) if err != nil { return nil, err } root.Certificate, err = helpers.ParseCertificatePEM(in) if err != nil { return nil, err } conf, err := config.LoadFile(configPath) if err != nil { return nil, err } root.Config = conf.Signing rootList[label] = &root } return rootList, nil }
// GetRemoteCA returns the remote endpoint's CA certificate func GetRemoteCA(ctx context.Context, d digest.Digest, r remotes.Remotes) (RootCA, error) { // This TLS Config is intentionally using InsecureSkipVerify. We use the // digest instead to check the integrity of the CA certificate. insecureCreds := credentials.NewTLS(&tls.Config{InsecureSkipVerify: true}) conn, peer, err := getGRPCConnection(insecureCreds, r) if err != nil { return RootCA{}, err } defer conn.Close() client := api.NewCAClient(conn) ctx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() defer func() { if err != nil { r.Observe(peer, -remotes.DefaultObservationWeight) return } r.Observe(peer, remotes.DefaultObservationWeight) }() response, err := client.GetRootCACertificate(ctx, &api.GetRootCACertificateRequest{}) if err != nil { return RootCA{}, err } if d != "" { verifier, err := digest.NewDigestVerifier(d) if err != nil { return RootCA{}, errors.Wrap(err, "unexpected error getting digest verifier") } io.Copy(verifier, bytes.NewReader(response.Certificate)) if !verifier.Verified() { return RootCA{}, errors.Errorf("remote CA does not match fingerprint. Expected: %s", d.Hex()) } } // Check the validity of the remote Cert _, err = helpers.ParseCertificatePEM(response.Certificate) if err != nil { return RootCA{}, err } // Create a Pool with our RootCACertificate pool := x509.NewCertPool() if !pool.AppendCertsFromPEM(response.Certificate) { return RootCA{}, errors.New("failed to append certificate to cert pool") } return RootCA{Cert: response.Certificate, Digest: digest.FromBytes(response.Certificate), Pool: pool}, nil }