Integrate BACKBEAT SDK and resolve KACHING license validation
Major integrations and fixes: - Added BACKBEAT SDK integration for P2P operation timing - Implemented beat-aware status tracking for distributed operations - Added Docker secrets support for secure license management - Resolved KACHING license validation via HTTPS/TLS - Updated docker-compose configuration for clean stack deployment - Disabled rollback policies to prevent deployment failures - Added license credential storage (CHORUS-DEV-MULTI-001) Technical improvements: - BACKBEAT P2P operation tracking with phase management - Enhanced configuration system with file-based secrets - Improved error handling for license validation - Clean separation of KACHING and CHORUS deployment stacks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
271
vendor/github.com/libp2p/go-libp2p/p2p/security/tls/crypto.go
generated
vendored
Normal file
271
vendor/github.com/libp2p/go-libp2p/p2p/security/tls/crypto.go
generated
vendored
Normal file
@@ -0,0 +1,271 @@
|
||||
package libp2ptls
|
||||
|
||||
import (
|
||||
"crypto"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
ic "github.com/libp2p/go-libp2p/core/crypto"
|
||||
"github.com/libp2p/go-libp2p/core/peer"
|
||||
"github.com/libp2p/go-libp2p/core/sec"
|
||||
)
|
||||
|
||||
const certValidityPeriod = 100 * 365 * 24 * time.Hour // ~100 years
|
||||
const certificatePrefix = "libp2p-tls-handshake:"
|
||||
const alpn string = "libp2p"
|
||||
|
||||
var extensionID = getPrefixedExtensionID([]int{1, 1})
|
||||
var extensionCritical bool // so we can mark the extension critical in tests
|
||||
|
||||
type signedKey struct {
|
||||
PubKey []byte
|
||||
Signature []byte
|
||||
}
|
||||
|
||||
// Identity is used to secure connections
|
||||
type Identity struct {
|
||||
config tls.Config
|
||||
}
|
||||
|
||||
// IdentityConfig is used to configure an Identity
|
||||
type IdentityConfig struct {
|
||||
CertTemplate *x509.Certificate
|
||||
}
|
||||
|
||||
// IdentityOption transforms an IdentityConfig to apply optional settings.
|
||||
type IdentityOption func(r *IdentityConfig)
|
||||
|
||||
// WithCertTemplate specifies the template to use when generating a new certificate.
|
||||
func WithCertTemplate(template *x509.Certificate) IdentityOption {
|
||||
return func(c *IdentityConfig) {
|
||||
c.CertTemplate = template
|
||||
}
|
||||
}
|
||||
|
||||
// NewIdentity creates a new identity
|
||||
func NewIdentity(privKey ic.PrivKey, opts ...IdentityOption) (*Identity, error) {
|
||||
config := IdentityConfig{}
|
||||
for _, opt := range opts {
|
||||
opt(&config)
|
||||
}
|
||||
|
||||
var err error
|
||||
if config.CertTemplate == nil {
|
||||
config.CertTemplate, err = certTemplate()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
cert, err := keyToCertificate(privKey, config.CertTemplate)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Identity{
|
||||
config: tls.Config{
|
||||
MinVersion: tls.VersionTLS13,
|
||||
InsecureSkipVerify: true, // This is not insecure here. We will verify the cert chain ourselves.
|
||||
ClientAuth: tls.RequireAnyClientCert,
|
||||
Certificates: []tls.Certificate{*cert},
|
||||
VerifyPeerCertificate: func(_ [][]byte, _ [][]*x509.Certificate) error {
|
||||
panic("tls config not specialized for peer")
|
||||
},
|
||||
NextProtos: []string{alpn},
|
||||
SessionTicketsDisabled: true,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ConfigForPeer creates a new single-use tls.Config that verifies the peer's
|
||||
// certificate chain and returns the peer's public key via the channel. If the
|
||||
// peer ID is empty, the returned config will accept any peer.
|
||||
//
|
||||
// It should be used to create a new tls.Config before securing either an
|
||||
// incoming or outgoing connection.
|
||||
func (i *Identity) ConfigForPeer(remote peer.ID) (*tls.Config, <-chan ic.PubKey) {
|
||||
keyCh := make(chan ic.PubKey, 1)
|
||||
// We need to check the peer ID in the VerifyPeerCertificate callback.
|
||||
// The tls.Config it is also used for listening, and we might also have concurrent dials.
|
||||
// Clone it so we can check for the specific peer ID we're dialing here.
|
||||
conf := i.config.Clone()
|
||||
// We're using InsecureSkipVerify, so the verifiedChains parameter will always be empty.
|
||||
// We need to parse the certificates ourselves from the raw certs.
|
||||
conf.VerifyPeerCertificate = func(rawCerts [][]byte, _ [][]*x509.Certificate) (err error) {
|
||||
defer func() {
|
||||
if rerr := recover(); rerr != nil {
|
||||
fmt.Fprintf(os.Stderr, "panic when processing peer certificate in TLS handshake: %s\n%s\n", rerr, debug.Stack())
|
||||
err = fmt.Errorf("panic when processing peer certificate in TLS handshake: %s", rerr)
|
||||
|
||||
}
|
||||
}()
|
||||
|
||||
defer close(keyCh)
|
||||
|
||||
chain := make([]*x509.Certificate, len(rawCerts))
|
||||
for i := 0; i < len(rawCerts); i++ {
|
||||
cert, err := x509.ParseCertificate(rawCerts[i])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
chain[i] = cert
|
||||
}
|
||||
|
||||
pubKey, err := PubKeyFromCertChain(chain)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if remote != "" && !remote.MatchesPublicKey(pubKey) {
|
||||
peerID, err := peer.IDFromPublicKey(pubKey)
|
||||
if err != nil {
|
||||
peerID = peer.ID(fmt.Sprintf("(not determined: %s)", err.Error()))
|
||||
}
|
||||
return sec.ErrPeerIDMismatch{Expected: remote, Actual: peerID}
|
||||
}
|
||||
keyCh <- pubKey
|
||||
return nil
|
||||
}
|
||||
return conf, keyCh
|
||||
}
|
||||
|
||||
// PubKeyFromCertChain verifies the certificate chain and extract the remote's public key.
|
||||
func PubKeyFromCertChain(chain []*x509.Certificate) (ic.PubKey, error) {
|
||||
if len(chain) != 1 {
|
||||
return nil, errors.New("expected one certificates in the chain")
|
||||
}
|
||||
cert := chain[0]
|
||||
pool := x509.NewCertPool()
|
||||
pool.AddCert(cert)
|
||||
var found bool
|
||||
var keyExt pkix.Extension
|
||||
// find the libp2p key extension, skipping all unknown extensions
|
||||
for _, ext := range cert.Extensions {
|
||||
if extensionIDEqual(ext.Id, extensionID) {
|
||||
keyExt = ext
|
||||
found = true
|
||||
for i, oident := range cert.UnhandledCriticalExtensions {
|
||||
if oident.Equal(ext.Id) {
|
||||
// delete the extension from UnhandledCriticalExtensions
|
||||
cert.UnhandledCriticalExtensions = append(cert.UnhandledCriticalExtensions[:i], cert.UnhandledCriticalExtensions[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
return nil, errors.New("expected certificate to contain the key extension")
|
||||
}
|
||||
if _, err := cert.Verify(x509.VerifyOptions{Roots: pool}); err != nil {
|
||||
// If we return an x509 error here, it will be sent on the wire.
|
||||
// Wrap the error to avoid that.
|
||||
return nil, fmt.Errorf("certificate verification failed: %s", err)
|
||||
}
|
||||
|
||||
var sk signedKey
|
||||
if _, err := asn1.Unmarshal(keyExt.Value, &sk); err != nil {
|
||||
return nil, fmt.Errorf("unmarshalling signed certificate failed: %s", err)
|
||||
}
|
||||
pubKey, err := ic.UnmarshalPublicKey(sk.PubKey)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unmarshalling public key failed: %s", err)
|
||||
}
|
||||
certKeyPub, err := x509.MarshalPKIXPublicKey(cert.PublicKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
valid, err := pubKey.Verify(append([]byte(certificatePrefix), certKeyPub...), sk.Signature)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("signature verification failed: %s", err)
|
||||
}
|
||||
if !valid {
|
||||
return nil, errors.New("signature invalid")
|
||||
}
|
||||
return pubKey, nil
|
||||
}
|
||||
|
||||
// GenerateSignedExtension uses the provided private key to sign the public key, and returns the
|
||||
// signature within a pkix.Extension.
|
||||
// This extension is included in a certificate to cryptographically tie it to the libp2p private key.
|
||||
func GenerateSignedExtension(sk ic.PrivKey, pubKey crypto.PublicKey) (pkix.Extension, error) {
|
||||
keyBytes, err := ic.MarshalPublicKey(sk.GetPublic())
|
||||
if err != nil {
|
||||
return pkix.Extension{}, err
|
||||
}
|
||||
certKeyPub, err := x509.MarshalPKIXPublicKey(pubKey)
|
||||
if err != nil {
|
||||
return pkix.Extension{}, err
|
||||
}
|
||||
signature, err := sk.Sign(append([]byte(certificatePrefix), certKeyPub...))
|
||||
if err != nil {
|
||||
return pkix.Extension{}, err
|
||||
}
|
||||
value, err := asn1.Marshal(signedKey{
|
||||
PubKey: keyBytes,
|
||||
Signature: signature,
|
||||
})
|
||||
if err != nil {
|
||||
return pkix.Extension{}, err
|
||||
}
|
||||
|
||||
return pkix.Extension{Id: extensionID, Critical: extensionCritical, Value: value}, nil
|
||||
}
|
||||
|
||||
// keyToCertificate generates a new ECDSA private key and corresponding x509 certificate.
|
||||
// The certificate includes an extension that cryptographically ties it to the provided libp2p
|
||||
// private key to authenticate TLS connections.
|
||||
func keyToCertificate(sk ic.PrivKey, certTmpl *x509.Certificate) (*tls.Certificate, error) {
|
||||
certKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// after calling CreateCertificate, these will end up in Certificate.Extensions
|
||||
extension, err := GenerateSignedExtension(sk, certKey.Public())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
certTmpl.ExtraExtensions = append(certTmpl.ExtraExtensions, extension)
|
||||
|
||||
certDER, err := x509.CreateCertificate(rand.Reader, certTmpl, certTmpl, certKey.Public(), certKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &tls.Certificate{
|
||||
Certificate: [][]byte{certDER},
|
||||
PrivateKey: certKey,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// certTemplate returns the template for generating an Identity's TLS certificates.
|
||||
func certTemplate() (*x509.Certificate, error) {
|
||||
bigNum := big.NewInt(1 << 62)
|
||||
sn, err := rand.Int(rand.Reader, bigNum)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
subjectSN, err := rand.Int(rand.Reader, bigNum)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &x509.Certificate{
|
||||
SerialNumber: sn,
|
||||
NotBefore: time.Now().Add(-time.Hour),
|
||||
NotAfter: time.Now().Add(certValidityPeriod),
|
||||
// According to RFC 3280, the issuer field must be set,
|
||||
// see https://datatracker.ietf.org/doc/html/rfc3280#section-4.1.2.4.
|
||||
Subject: pkix.Name{SerialNumber: subjectSN.String()},
|
||||
}, nil
|
||||
}
|
||||
Reference in New Issue
Block a user