storj/pkg/peertls/generate.go
Cameron 6463b87ebe
Errcheck (#133)
* add errcheck

* fixed linter errors

* fixes

* errcheck fixes in pkg/paths

* Fix errchecks in PieceID.Derive

* Fix ecclient tests

* Move closeConn a little bit above in the exectution flow

* fix new lint errors

* Fatalf -> Printf

* address eclipsed errors

* rename err to closeErr

* rename err to closeErr for differentiation
2018-07-16 15:22:34 -04:00

175 lines
3.9 KiB
Go

// Copyright (C) 2018 Storj Labs, Inc.
// See LICENSE for copying information.
package peertls
// Many cryptography standards use ASN.1 to define their data structures,
// and Distinguished Encoding Rules (DER) to serialize those structures.
// Because DER produces binary output, it can be challenging to transmit
// the resulting files through systems, like electronic mail, that only
// support ASCII. The PEM format solves this problem by encoding the
// binary data using base64.
// (see https://en.wikipedia.org/wiki/Privacy-enhanced_Electronic_Mail)
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"io/ioutil"
"math/big"
"time"
"github.com/zeebo/errs"
)
const (
// OneYear is the integer represtentation of a calendar year
OneYear = 365 * 24 * time.Hour
)
func (t *TLSFileOptions) generateTLS() error {
if err := t.EnsureAbsPaths(); err != nil {
return ErrGenerate.Wrap(err)
}
rootKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return ErrGenerate.New("failed to generateServerTLS root private key", err)
}
rootT, err := rootTemplate(t)
if err != nil {
return ErrGenerate.Wrap(err)
}
rootC, err := createAndWrite(
t.RootCertAbsPath,
t.RootKeyAbsPath,
rootT,
rootT,
nil,
&rootKey.PublicKey,
rootKey,
rootKey,
)
if err != nil {
return ErrGenerate.Wrap(err)
}
newKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return ErrGenerate.New("failed to generateTLS client private key", err)
}
leafT, err := leafTemplate(t)
if err != nil {
return ErrGenerate.Wrap(err)
}
leafC, err := createAndWrite(
t.LeafCertAbsPath,
t.LeafKeyAbsPath,
leafT,
rootT,
rootC.Certificate,
&newKey.PublicKey,
rootKey,
newKey,
)
if err != nil {
return ErrGenerate.Wrap(err)
}
t.LeafCertificate = leafC
return nil
}
// LoadCert reads and parses a cert/privkey pair from a pair
// of files. The files must contain PEM encoded data. The certificate file
// may contain intermediate certificates following the leaf certificate to
// form a certificate chain. On successful return, Certificate.Leaf will
// be nil because the parsed form of the certificate is not retained.
func LoadCert(certFile, keyFile string) (*tls.Certificate, error) {
certPEMBytes, err := ioutil.ReadFile(certFile)
if err != nil {
return &tls.Certificate{}, err
}
keyPEMBytes, err := ioutil.ReadFile(keyFile)
if err != nil {
return &tls.Certificate{}, err
}
return certFromPEMs(certPEMBytes, keyPEMBytes)
}
func createAndWrite(
certPath,
keyPath string,
template,
parentTemplate *x509.Certificate,
parentDERCerts [][]byte,
pubKey *ecdsa.PublicKey,
rootKey,
privKey *ecdsa.PrivateKey) (*tls.Certificate, error) {
DERCerts, keyDERBytes, err := createDERs(
template,
parentTemplate,
parentDERCerts,
pubKey,
rootKey,
privKey,
)
if err != nil {
return nil, err
}
if err := writeCerts(DERCerts, certPath); err != nil {
return nil, err
}
if err := writeKey(privKey, keyPath); err != nil {
return nil, err
}
return certFromDERs(DERCerts, keyDERBytes)
}
func createDERs(
template,
parentTemplate *x509.Certificate,
parentDERCerts [][]byte,
pubKey *ecdsa.PublicKey,
rootKey,
privKey *ecdsa.PrivateKey) (_ [][]byte, _ []byte, _ error) {
certDERBytes, err := x509.CreateCertificate(rand.Reader, template, parentTemplate, pubKey, rootKey)
if err != nil {
return nil, nil, err
}
DERCerts := [][]byte{}
DERCerts = append(DERCerts, certDERBytes)
DERCerts = append(DERCerts, parentDERCerts...)
keyDERBytes, err := keyToDERBytes(privKey)
if err != nil {
return nil, nil, err
}
return DERCerts, keyDERBytes, nil
}
func newSerialNumber() (*big.Int, error) {
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return nil, errs.New("failed to generateServerTls serial number: %s", err.Error())
}
return serialNumber, nil
}