5b913c45b9
* wip initial transport security * wip: transport security (add tests / refactor) * wip tests * refactoring - still wip * refactor, improve tests * wip tls testing * fix typo * wip testing * wip testing * wip * tls_test passing * code-style improvemente / refactor; service and tls tests passing! * code-style auto-format * add TestNewServer_LoadTLS * refactor; test improvements * refactor * add client cert * port changes * Merge remote-tracking branch 'upstream/master' * Merge remote-tracking branch 'upstream/master' * Merge remote-tracking branch 'upstream/master' * files created * Merge remote-tracking branch 'upstream/master' into coyle/kad-tests * wip * add separate `Process` tests for bolt and redis-backed overlay * more testing * fix gitignore * fix linter error * goimports goimports GOIMPORTS GoImPortS!!!! * wip * fix port madness * forgot to add * add `mux` as handler and shorten context timeouts * gofreakingimports * fix comments * refactor test & add logger/monkit registry * debugging travis * add comment * Set redisAddress to empty string for bolt-test * Merge remote-tracking branch 'upstream/master' into coyle/kad-tests * Merge branch 'tls' into tls-upstream * tls: add client cert refactor refactor; test improvements add TestNewServer_LoadTLS code-style auto-format code-style improvemente / refactor; service and tls tests passing! tls_test passing wip wip testing wip testing fix typo wip tls testing refactor, improve tests refactoring - still wip wip tests wip: transport security (add tests / refactor) wip initial transport security * fixing linter things * wip * remove bkad dependencie from tests * wip * wip * wip * wip * wip * updated coyle/kademlia * wip * cleanup * ports * overlay upgraded * linter fixes * piecestore kademlia newID * Merge branch 'master' into tls-upstream * master: Add error to the return values of Ranger.Range method (#90) udp-forwarding: demo week work! (#84) * Merge branch 'kad-tests' into tls-upstream * kad-tests: piecestore kademlia newID linter fixes overlay upgraded ports cleanup wip updated coyle/kademlia wip wip wip wip wip remove bkad dependencie from tests wip wip files created port changes * wip * finish merging service tests * add test for different client/server certs * wip * Merge branch 'master' into tls-upstream * master: Add context to Ranger.Range method (#99) Coyle/kad client (#91) * wip * wip; refactoring/cleanup * wip * Merge branch 'master' into tls * master: Bolt backed overlay cache (#94) internal/test: switch errors to error classes (#96) * wip - test passing * cleanup * remove port.go * cleanup * Merge branch 'master' into tls * master: hardcode version (#111) Coyle/docker fix (#109) pkg/kademlia tests and restructuring (#97) Use continue instead of return in table tests (#106) prepend storjlabs to docker tag (#108) Automatically build, tag and push docker images on merge to master (#103) * more belated merging * more belated merging * more belated merging * add copyrights * cleanup * goimports * refactoring * wip * wip * implement `TLSFileOptions#loadTLS`, refactoring: `peertls.TestNewClient_LoadTLS` is the failing holdout; Still trying to figure out why I'm getting ECDSA verification is failing. * not sure if actually working: Tests are now passing (no more "ECDSA verification failed"); however, `len(*tls.Certificates.Certificate) == 1` which I don't think should be the case if the root and leaf are being created correctly. * Experimenting/bugfixing?: I think leaf certs should be properly signed by the parent now but not entirely certain. It's also unclear to me why in `VerifyPeerCertificate`, `len(rawCerts) == 1` when the certs should contain both the root and leaf afaik. * Properly write/read certificate chain (root/leaf): I think I'm now properly reading and writing the root and leaf certificate chain such that they're both being received by `VerifyPeerCertificate`. The next step is to parse the certificates with `x509.ParseCertificate` (or similar) and verify that the public keys and signatures match. * Add tls certificate chain signature veification (spike): + `VerifyPeerCertificate` verifies signatures of certificates using the key of it's parent if there is one; otherwise, it verifies the certificate is self-signed + TODO: refactor + TODO: test * refactoring `VerifyPeerCertificate` * cleanup * refactor * Merge branch 'master' into tls * master: Remove some structural folders we don't seem to be using. (#125) license code with agplv3 (#126) Update .clabot (#124) added team memebers (#123) clabot file added (#121) ECClient (#110) docker image issue fixed (#118) Piecestore Farmer CLI (#92) Define Path type (#101) adds netstate pagination (#95) Transport Client (#89) Implement psclient interface (#107) pkg/process: start replacing pkg/process with cobra helpers (#98) protos/netstate: remove stuff we're not using (#100) adding coveralls / code coverage (#112) * responding to review feedback / cleanup / add copywrite headers * suggestions * realitive * Merge pull request #1 from coyle/coyle/tls suggestions * remove unnecessary `_`s * Merge branch 'tls' of github.com:bryanchriswhite/storj into tls * 'tls' of github.com:bryanchriswhite/storj: realitive suggestions * Responding to review feedback: + refactor `VerifyPeerCertificate` * remove tls expiration * remove "hosts" and "clien option" from tls options * goimports * linter fixes
174 lines
3.8 KiB
Go
174 lines
3.8 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 = 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
|
|
}
|