Files
netbird/management/internals/shared/grpc/certposture.go
T

73 lines
2.2 KiB
Go

package grpc
import (
"context"
"crypto/sha256"
"time"
log "github.com/sirupsen/logrus"
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
"github.com/netbirdio/netbird/shared/management/certposture"
"github.com/netbirdio/netbird/shared/management/proto"
)
const certChallengeKeyDomain = "netbird-cert-challenge-key"
// certChallenger derives the nonce secret from the management WireGuard key so every
// instance sharing that key issues and verifies the same nonces without extra state.
func certChallenger(serverKey wgtypes.Key) *certposture.Challenger {
h := sha256.New()
h.Write([]byte(certChallengeKeyDomain))
h.Write(serverKey[:])
return certposture.NewChallenger(h.Sum(nil))
}
// stampCertificateChallenges fills the per-peer nonce into every certificate challenge
// right before the response is encrypted for that peer.
func stampCertificateChallenges(checks []*proto.Checks, peerKey, serverKey wgtypes.Key) {
var nonce []byte
for _, check := range checks {
challenge := check.GetCertificateChallenge()
if challenge == nil {
continue
}
if nonce == nil {
nonce = certChallenger(serverKey).Nonce(peerKey[:], time.Now())
}
challenge.Nonce = nonce
}
}
// verifiedCertificates turns the peer's proofs into PEM chains for its meta. Possession
// (nonce + signature) is verified here; trust against a check's CAs is evaluated by the
// posture check itself. Any invalid proof rejects the whole set.
func (s *Server) verifiedCertificates(ctx context.Context, peerKey wgtypes.Key, proofs []*proto.CertificateProof) []string {
if len(proofs) == 0 {
return nil
}
serverKey, err := s.secretsManager.GetWGKey()
if err != nil {
log.WithContext(ctx).Warnf("skipping certificate proofs of peer %s: %v", peerKey, err)
return nil
}
challenger := certChallenger(serverKey)
now := time.Now()
chains := make([]string, 0, len(proofs))
for _, p := range proofs {
chain, err := challenger.Verify(certposture.Proof{
Nonce: p.GetNonce(),
Chain: p.GetChain(),
SigAlg: p.GetSigAlg(),
Signature: p.GetSignature(),
}, peerKey[:], now)
if err != nil {
log.WithContext(ctx).Warnf("rejecting certificate proofs of peer %s: %v", peerKey, err)
return nil
}
chains = append(chains, certposture.EncodeChainPEM(chain))
}
return chains
}