Skip to content

Commit

Permalink
Merge pull request #2 from madflojo/tempfiles
Browse files Browse the repository at this point in the history
Adding ability to create random files
  • Loading branch information
madflojo authored Jan 29, 2023
2 parents fbcecb0 + ac25887 commit f53d6d8
Show file tree
Hide file tree
Showing 3 changed files with 259 additions and 47 deletions.
84 changes: 73 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,82 @@
[![Coverage Status](https://coveralls.io/repos/github/madflojo/testcerts/badge.svg?branch=master)](https://coveralls.io/github/madflojo/testcerts?branch=master) [![Go Report Card](https://goreportcard.com/badge/github.com/madflojo/testcerts)](https://goreportcard.com/report/github.com/madflojo/testcerts) [![Documentation](https://godoc.org/github.com/madflojo/testcerts?status.svg)](http://godoc.org/github.com/madflojo/testcerts)
[![license](https://img.shields.io/github/license/madflojo/testcerts.svg?maxAge=2592000)](https://github.com/madflojo/testcerts/LICENSE)

A Go package for creating temporary x509 test certificates
testcerts is a Go package that makes it easy for developers to generate x509 certificates for testing and development purposes. The package provides an easy-to-use API for generating self-signed certificates and keys for testing.

There are many Certificate generation tools out there, but most focus on being a CLI tool. This package is focused on providing helper functions for creating Certificates. These helper functions can be used as part of Go tests per the example below.
What makes testcerts unique is its ability to generate certificates and keys with a single line of code, and also its ability to handle saving them to temp and non-temp files, which eliminates the need for developers to handle file operations while testing their code.

Overall, testcerts simplifies the process of generating and managing test certificates, making it a valuable tool for any developer working with x509 certificates.

## Usage

### Generating Certificates to File

The `GenerateCertsToFile` function generates an X.509 certificate and key and writes them to the file paths provided.

```go
func TestSomething(t *testing.T) {
err := testcerts.GenerateCertsToFile("/tmp/cert", "/tmp/key")
if err != nil {
// do stuff
}

_ = something.Run("/tmp/cert", "/tmp/key")
// do more testing
package main

import (
"github.com/madflojo/testcerts"
)

func main() {
err := testcerts.GenerateCertsToFile("/tmp/cert.pem", "/tmp/key.pem")
if err != nil {
// handle error
}
}
```

The goal of this package, is to make testing TLS based services easier. Without having to leave the comfort of your editor, or place test certificates in your repo.
### Generating Certificates to Temporary File

The `GenerateCertsToTempFile` function generates an X.509 certificate and key and writes them to randomly generated files in the directory provided or the system's temporary directory if none is provided. The function returns the file paths of the generated files.

```go
package main

import (
"github.com/madflojo/testcerts"
)

func main() {
certFile, keyFile, err := testcerts.GenerateCertsToTempFile("/tmp/")
if err != nil {
// handle error
}
}
```

### Generating Certificates

The `GenerateCerts` function generates an X.509 certificate and key and returns them as byte slices.

```go
package main

import (
"fmt"

"github.com/madflojo/testcerts"
)

func main() {
cert, key, err := testcerts.GenerateCerts()
if err != nil {
// handle error
}
fmt.Printf("Certificate: %s\n", cert)
fmt.Printf("Key: %s\n", key)
}
```

## Contributing

If you find a bug or have an idea for a feature, please open an issue or a pull request.

## License

testcerts is released under the MIT License. See [LICENSE](./LICENSE) for details.



111 changes: 82 additions & 29 deletions testcerts.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,32 @@
// Package testcerts enables users to create temporary x509 Certificates for testing.
//
// There are many Certificate generation tools out there, but most focus on being a CLI tool. This package is focused
// on providing helper functions for creating Certificates. These helper functions can be used as part of your unit
// and integration tests as per the example below.
//
// func TestSomething(t *testing.T) {
// err := testcerts.GenerateCertsToFile("/tmp/cert", "/tmp/key")
// if err != nil {
// // do stuff
// }
//
// _ = something.Run("/tmp/cert", "/tmp/key")
// // do more testing
// }
//
// The goal of this package, is to make testing TLS based services easier. Without having to leave the comfort of your
// editor, or place test certificates in your repo.
/*
Package testcerts provides a set of functions for generating and saving x509 test certificates to file.
This package can be used in testing and development environments where a set of trusted certificates are needed.
The main function, GenerateCertsToTempFile, generates an x509 certificate and key and writes them to a randomly
named file in a specified or temporary directory.
For example, to generate and save a certificate and key to a temporary directory:
package main
import (
"fmt"
"log"
"testcerts"
)
func main() {
certPath, keyPath, err := testcerts.GenerateCertsToTempFile("")
if err != nil {
log.Fatal(err)
}
fmt.Println("Certificate written to:", certPath)
fmt.Println("Key written to:", keyPath)
}
This will create a temporary certificate and key and print the paths to where the files were written.
*/
package testcerts

import (
Expand All @@ -30,11 +41,12 @@ import (
"time"
)

// GenerateCerts will create a temporary x509 Certificate and Key.
// GenerateCerts generates an x509 certificate and key.
// It returns the certificate and key as byte slices, and any error that occurred.
//
// cert, key, err := GenerateCerts()
// if err != nil {
// // do stuff
// // handle error
// }
func GenerateCerts() ([]byte, []byte, error) {
// Create certs and return as []byte
Expand All @@ -45,44 +57,85 @@ func GenerateCerts() ([]byte, []byte, error) {
return pem.EncodeToMemory(c), pem.EncodeToMemory(k), nil
}

// GenerateCertsToFile will create a temporary x509 Certificate and Key. Writing them to the file provided.
// GenerateCertsToFile creates an x509 certificate and key and writes it to the specified file paths.
//
// err := GenerateCertsToFile("/path/to/cert", "/path/to/key")
// if err != nil {
// // do stuff
// // handle error
// }
//
// If the specified file paths already exist, it will overwrite the existing files.
func GenerateCertsToFile(certFile, keyFile string) error {
// Create Certs
c, k, err := genCerts()
c, k, err := GenerateCerts()
if err != nil {
return err
}

// Write to Certificate File
// Write Certificate
cfh, err := os.Create(certFile)
if err != nil {
return fmt.Errorf("unable to create certificate file - %s", err)
}
defer cfh.Close()
err = pem.Encode(cfh, c)
_, err = cfh.Write(c)
if err != nil {
return fmt.Errorf("unable to create certificate file - %s", err)
}

// Write to Key File
// Write Key
kfh, err := os.Create(keyFile)
if err != nil {
return fmt.Errorf("unable to create certificate file - %s", err)
}
defer kfh.Close()
err = pem.Encode(kfh, k)
_, err = kfh.Write(k)
if err != nil {
return fmt.Errorf("unable to create certificate file - %s", err)
}

return nil
}

// GenerateCertsToTempFile will create a temporary x509 certificate and key in a randomly generated file using the
// directory path provided. If no directory is specified, the default directory for temporary files as returned by
// os.TempDir will be used.
//
// cert, key, err := GenerateCertsToTempFile("/tmp/")
// if err != nil {
// // handle error
// }
func GenerateCertsToTempFile(dir string) (string, string, error) {
// Create Certs
c, k, err := GenerateCerts()
if err != nil {
return "", "", err
}

cfh, err := os.CreateTemp(dir, "*.cert")
if err != nil {
return "", "", fmt.Errorf("could not create temporary file - %s", err)
}
defer cfh.Close()
_, err = cfh.Write(c)
if err != nil {
return cfh.Name(), "", fmt.Errorf("unable to create certificate file - %s", err)
}

// Write to Key File
kfh, err := os.CreateTemp(dir, "*.key")
if err != nil {
return cfh.Name(), "", fmt.Errorf("unable to create certificate file - %s", err)
}
defer kfh.Close()
_, err = kfh.Write(k)
if err != nil {
return cfh.Name(), kfh.Name(), fmt.Errorf("unable to create certificate file - %s", err)
}

return cfh.Name(), kfh.Name(), nil
}

// genCerts will perform the task of creating a temporary Certificate and Key.
func genCerts() (*pem.Block, *pem.Block, error) {
// Create a Certificate Authority Cert
Expand All @@ -101,14 +154,14 @@ func genCerts() (*pem.Block, *pem.Block, error) {
// Create a Private Key
key, err := rsa.GenerateKey(rand.Reader, 4096)
if err != nil {
return nil, nil, fmt.Errorf("Could not generate rsa key - %s", err)
return nil, nil, fmt.Errorf("could not generate rsa key - %s", err)
}

// Use CA Cert to sign a CSR and create a Public Cert
csr := &key.PublicKey
cert, err := x509.CreateCertificate(rand.Reader, ca, ca, csr, key)
if err != nil {
return nil, nil, fmt.Errorf("Could not generate certificate - %s", err)
return nil, nil, fmt.Errorf("could not generate certificate - %s", err)
}

// Convert keys into pem.Block
Expand Down
Loading

0 comments on commit f53d6d8

Please sign in to comment.