2019-01-24 20:15:10 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
2018-08-13 09:39:45 +01:00
|
|
|
// 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 (
|
2019-04-03 16:03:53 +01:00
|
|
|
"crypto"
|
2018-08-13 09:39:45 +01:00
|
|
|
"crypto/rand"
|
2019-04-03 16:03:53 +01:00
|
|
|
"crypto/sha256"
|
2018-08-13 09:39:45 +01:00
|
|
|
"crypto/x509"
|
|
|
|
"math/big"
|
|
|
|
|
|
|
|
"github.com/zeebo/errs"
|
|
|
|
|
2019-02-07 09:04:29 +00:00
|
|
|
"storj.io/storj/pkg/pkcrypto"
|
|
|
|
)
|
2018-08-13 09:39:45 +01:00
|
|
|
|
2019-02-26 18:35:16 +00:00
|
|
|
// NonTemporaryError is an error with a `Temporary` method which always returns false.
|
|
|
|
// It is intended for use with grpc.
|
|
|
|
//
|
|
|
|
// (see https://godoc.org/google.golang.org/grpc#WithDialer
|
|
|
|
// and https://godoc.org/google.golang.org/grpc#FailOnNonTempDialError).
|
|
|
|
type NonTemporaryError struct{ error }
|
|
|
|
|
|
|
|
// NewNonTemporaryError returns a new temporary error for use with grpc.
|
|
|
|
func NewNonTemporaryError(err error) NonTemporaryError {
|
|
|
|
return NonTemporaryError{
|
|
|
|
error: errs.Wrap(err),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-03 16:03:53 +01:00
|
|
|
// DoubleSHA256PublicKey returns the hash of the hash of (double-hash, SHA226)
|
|
|
|
// the binary format of the given public key.
|
|
|
|
func DoubleSHA256PublicKey(k crypto.PublicKey) ([sha256.Size]byte, error) {
|
|
|
|
kb, err := x509.MarshalPKIXPublicKey(k)
|
|
|
|
if err != nil {
|
|
|
|
return [sha256.Size]byte{}, err
|
|
|
|
}
|
|
|
|
mid := sha256.Sum256(kb)
|
|
|
|
end := sha256.Sum256(mid[:])
|
|
|
|
return end, nil
|
|
|
|
}
|
|
|
|
|
2019-02-26 18:35:16 +00:00
|
|
|
// Temporary returns false to indicate that is is a non-temporary error
|
|
|
|
func (nte NonTemporaryError) Temporary() bool {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// Err returns the underlying error
|
|
|
|
func (nte NonTemporaryError) Err() error {
|
|
|
|
return nte.error
|
|
|
|
}
|
|
|
|
|
2018-08-13 09:39:45 +01:00
|
|
|
func verifyChainSignatures(certs []*x509.Certificate) error {
|
|
|
|
for i, cert := range certs {
|
|
|
|
j := len(certs)
|
|
|
|
if i+1 < j {
|
2018-10-26 14:52:37 +01:00
|
|
|
err := verifyCertSignature(certs[i+1], cert)
|
2018-08-13 09:39:45 +01:00
|
|
|
if err != nil {
|
2018-10-26 14:52:37 +01:00
|
|
|
return ErrVerifyCertificateChain.Wrap(err)
|
2018-08-13 09:39:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2018-10-26 14:52:37 +01:00
|
|
|
err := verifyCertSignature(cert, cert)
|
2018-08-13 09:39:45 +01:00
|
|
|
if err != nil {
|
2018-10-26 14:52:37 +01:00
|
|
|
return ErrVerifyCertificateChain.Wrap(err)
|
2018-08-13 09:39:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-10-26 14:52:37 +01:00
|
|
|
func verifyCertSignature(parentCert, childCert *x509.Certificate) error {
|
2019-02-07 20:39:20 +00:00
|
|
|
return pkcrypto.HashAndVerifySignature(parentCert.PublicKey, childCert.RawTBSCertificate, childCert.Signature)
|
2018-08-13 09:39:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
}
|