166 lines
2.8 KiB
Go
166 lines
2.8 KiB
Go
|
// Copyright (C) 2018 Storj Labs, Inc.
|
||
|
// See LICENSE for copying information.
|
||
|
|
||
|
package provider
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"crypto"
|
||
|
"crypto/ecdsa"
|
||
|
"crypto/x509"
|
||
|
"encoding/base64"
|
||
|
"encoding/pem"
|
||
|
"os"
|
||
|
"path/filepath"
|
||
|
|
||
|
"github.com/zeebo/errs"
|
||
|
"golang.org/x/crypto/sha3"
|
||
|
|
||
|
"storj.io/storj/pkg/peertls"
|
||
|
)
|
||
|
|
||
|
type TlsFilesStat int
|
||
|
|
||
|
const (
|
||
|
NoCertNoKey = iota
|
||
|
CertNoKey
|
||
|
NoCertKey
|
||
|
CertKey
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
ErrZeroBytes = errs.New("byte slice was unexpectedly empty")
|
||
|
)
|
||
|
|
||
|
func decodePEM(PEMBytes []byte) ([][]byte, error) {
|
||
|
DERBytes := [][]byte{}
|
||
|
|
||
|
for {
|
||
|
var DERBlock *pem.Block
|
||
|
|
||
|
DERBlock, PEMBytes = pem.Decode(PEMBytes)
|
||
|
if DERBlock == nil {
|
||
|
break
|
||
|
}
|
||
|
|
||
|
DERBytes = append(DERBytes, DERBlock.Bytes)
|
||
|
}
|
||
|
|
||
|
if len(DERBytes) == 0 || len(DERBytes[0]) == 0 {
|
||
|
return nil, ErrZeroBytes
|
||
|
}
|
||
|
|
||
|
return DERBytes, nil
|
||
|
}
|
||
|
|
||
|
func generateCAWorker(ctx context.Context, difficulty uint16, caC chan FullCertificateAuthority, eC chan error) {
|
||
|
var (
|
||
|
k crypto.PrivateKey
|
||
|
i nodeID
|
||
|
err error
|
||
|
)
|
||
|
for {
|
||
|
select {
|
||
|
case <-ctx.Done():
|
||
|
return
|
||
|
default:
|
||
|
k, err = peertls.NewKey()
|
||
|
switch kE := k.(type) {
|
||
|
case *ecdsa.PrivateKey:
|
||
|
i, err = idFromKey(&kE.PublicKey)
|
||
|
if err != nil {
|
||
|
eC <- err
|
||
|
return
|
||
|
}
|
||
|
default:
|
||
|
eC <- peertls.ErrUnsupportedKey.New("%T", k)
|
||
|
return
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if i.Difficulty() >= difficulty {
|
||
|
break
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ct, err := peertls.CATemplate()
|
||
|
if err != nil {
|
||
|
eC <- err
|
||
|
return
|
||
|
}
|
||
|
|
||
|
c, err := peertls.NewCert(ct, nil, k)
|
||
|
if err != nil {
|
||
|
eC <- err
|
||
|
return
|
||
|
}
|
||
|
|
||
|
ca := FullCertificateAuthority{
|
||
|
Cert: c,
|
||
|
Key: k,
|
||
|
ID: i,
|
||
|
}
|
||
|
caC <- ca
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func idFromKey(k crypto.PublicKey) (nodeID, error) {
|
||
|
kb, err := x509.MarshalPKIXPublicKey(k)
|
||
|
if err != nil {
|
||
|
return "", errs.Wrap(err)
|
||
|
}
|
||
|
hash := make([]byte, IdentityLength)
|
||
|
sha3.ShakeSum256(hash, kb)
|
||
|
return nodeID(base64.URLEncoding.EncodeToString(hash)), nil
|
||
|
}
|
||
|
|
||
|
func openCert(path string, flag int) (*os.File, error) {
|
||
|
if err := os.MkdirAll(filepath.Dir(path), 744); err != nil {
|
||
|
return nil, errs.Wrap(err)
|
||
|
}
|
||
|
|
||
|
c, err := os.OpenFile(path, flag, 0644)
|
||
|
if err != nil {
|
||
|
return nil, errs.New("unable to open cert file for writing \"%s\"", path, err)
|
||
|
}
|
||
|
return c, nil
|
||
|
}
|
||
|
|
||
|
func openKey(path string, flag int) (*os.File, error) {
|
||
|
if err := os.MkdirAll(filepath.Dir(path), 700); err != nil {
|
||
|
return nil, errs.Wrap(err)
|
||
|
}
|
||
|
|
||
|
k, err := os.OpenFile(path, flag, 0600)
|
||
|
if err != nil {
|
||
|
return nil, errs.New("unable to open key file for writing \"%s\"", path, err)
|
||
|
}
|
||
|
return k, nil
|
||
|
}
|
||
|
|
||
|
func statTLSFiles(certPath, keyPath string) TlsFilesStat {
|
||
|
s := 0
|
||
|
_, err := os.Stat(certPath)
|
||
|
if err == nil {
|
||
|
s += 1
|
||
|
}
|
||
|
_, err = os.Stat(keyPath)
|
||
|
if err == nil {
|
||
|
s += 2
|
||
|
}
|
||
|
return TlsFilesStat(s)
|
||
|
}
|
||
|
|
||
|
func (t TlsFilesStat) String() string {
|
||
|
switch t {
|
||
|
case CertKey:
|
||
|
return "certificate and key"
|
||
|
case CertNoKey:
|
||
|
return "certificate"
|
||
|
case NoCertKey:
|
||
|
return "key"
|
||
|
default:
|
||
|
return ""
|
||
|
}
|
||
|
}
|