mirror of
https://github.com/netbirdio/netbird.git
synced 2026-10-10 23:49:09 +02:00
Log certificate posture details at debug level
This commit is contained in:
@@ -25,14 +25,14 @@ func Collect(ctx context.Context, store Store, checks []*proto.Checks, peerKey [
|
||||
|
||||
func logNoChallenges(checks []*proto.Checks) {
|
||||
if len(checks) > 0 {
|
||||
log.Infof("certificate posture: %d posture checks received, none carries a certificate challenge", len(checks))
|
||||
log.Debugf("certificate posture: %d posture checks received, none carries a certificate challenge", len(checks))
|
||||
}
|
||||
}
|
||||
|
||||
// CollectChallenges answers challenges already extracted from the posture checks, so a
|
||||
// caller that ships them across a process boundary reuses the same matching and signing.
|
||||
func CollectChallenges(ctx context.Context, store Store, challenges []*proto.CertificateChallenge, peerKey []byte) []certposture.Proof {
|
||||
log.Infof("certificate posture: answering %d certificate challenges from store %T", len(challenges), store)
|
||||
log.Debugf("certificate posture: answering %d certificate challenges from store %T", len(challenges), store)
|
||||
|
||||
candidates, err := store.Candidates(ctx)
|
||||
if err != nil {
|
||||
@@ -40,10 +40,10 @@ func CollectChallenges(ctx context.Context, store Store, challenges []*proto.Cer
|
||||
return nil
|
||||
}
|
||||
if len(candidates) == 0 {
|
||||
log.Info("certificate posture: certificate store holds no candidates, no proof will be sent")
|
||||
log.Debug("certificate posture: certificate store holds no candidates, no proof will be sent")
|
||||
return nil
|
||||
}
|
||||
log.Infof("certificate posture: store holds %d candidate certificates", len(candidates))
|
||||
log.Debugf("certificate posture: store holds %d candidate certificates", len(candidates))
|
||||
|
||||
now := time.Now()
|
||||
proven := make(map[[sha256.Size]byte]struct{})
|
||||
@@ -54,7 +54,7 @@ func CollectChallenges(ctx context.Context, store Store, challenges []*proto.Cer
|
||||
log.Warnf("skipping certificate challenge with invalid CA certificates: %v", err)
|
||||
continue
|
||||
}
|
||||
log.Infof("certificate posture: challenge %d accepts %d CA certificates, nonce is %d bytes", i, len(challenge.GetCaCertificates()), len(challenge.GetNonce()))
|
||||
log.Debugf("certificate posture: challenge %d accepts %d CA certificates, nonce is %d bytes", i, len(challenge.GetCaCertificates()), len(challenge.GetNonce()))
|
||||
|
||||
matched := false
|
||||
for _, candidate := range candidates {
|
||||
@@ -63,14 +63,14 @@ func CollectChallenges(ctx context.Context, store Store, challenges []*proto.Cer
|
||||
}
|
||||
leaf := candidate.Chain[0]
|
||||
if err := certposture.VerifyChain(candidate.Chain, roots, now); err != nil {
|
||||
log.Infof("certificate posture: challenge %d rejected %q issued by %q, chain of %d: %v", i, leaf.Subject, leaf.Issuer, len(candidate.Chain), err)
|
||||
log.Debugf("certificate posture: challenge %d rejected %q issued by %q, chain of %d: %v", i, leaf.Subject, leaf.Issuer, len(candidate.Chain), err)
|
||||
continue
|
||||
}
|
||||
matched = true
|
||||
|
||||
fingerprint := sha256.Sum256(leaf.Raw)
|
||||
if _, done := proven[fingerprint]; done {
|
||||
log.Infof("certificate posture: challenge %d matched %q, already proven for an earlier challenge", i, leaf.Subject)
|
||||
log.Debugf("certificate posture: challenge %d matched %q, already proven for an earlier challenge", i, leaf.Subject)
|
||||
break
|
||||
}
|
||||
proof, err := prove(candidate, challenge.GetNonce(), peerKey)
|
||||
@@ -78,16 +78,16 @@ func CollectChallenges(ctx context.Context, store Store, challenges []*proto.Cer
|
||||
log.Warnf("failed signing certificate proof for %s: %v", leaf.Subject, err)
|
||||
continue
|
||||
}
|
||||
log.Infof("certificate posture: challenge %d proven by %q with %s, signature %d bytes, chain of %d", i, leaf.Subject, proof.SigAlg, len(proof.Signature), len(proof.Chain))
|
||||
log.Debugf("certificate posture: challenge %d proven by %q with %s, signature %d bytes, chain of %d", i, leaf.Subject, proof.SigAlg, len(proof.Signature), len(proof.Chain))
|
||||
proven[fingerprint] = struct{}{}
|
||||
proofs = append(proofs, proof)
|
||||
break
|
||||
}
|
||||
if !matched {
|
||||
log.Infof("certificate posture: challenge %d matched none of the %d candidates", i, len(candidates))
|
||||
log.Debugf("certificate posture: challenge %d matched none of the %d candidates", i, len(candidates))
|
||||
}
|
||||
}
|
||||
log.Infof("certificate posture: %d challenges produced %d proofs", len(challenges), len(proofs))
|
||||
log.Debugf("certificate posture: %d challenges produced %d proofs", len(challenges), len(proofs))
|
||||
return proofs
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ func CollectProofs(ctx context.Context, checks []*proto.Checks, peerKey []byte,
|
||||
|
||||
userProofs, err := collectAsConsoleUser(ctx, challenges, peerKey)
|
||||
if err != nil {
|
||||
log.Infof("certificate posture: console user keychain unavailable: %v", err)
|
||||
log.Debugf("certificate posture: console user keychain unavailable: %v", err)
|
||||
}
|
||||
return mergeProofs(proofs, userProofs)
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ func CollectProofs(ctx context.Context, checks []*proto.Checks, peerKey []byte,
|
||||
|
||||
userProofs, err := collectAsDesktopUser(ctx, challenges, peerKey)
|
||||
if err != nil {
|
||||
log.Infof("certificate posture: user certificate store unavailable: %v", err)
|
||||
log.Debugf("certificate posture: user certificate store unavailable: %v", err)
|
||||
}
|
||||
return mergeProofs(proofs, userProofs)
|
||||
}
|
||||
|
||||
@@ -37,21 +37,21 @@ type ConsoleUser struct {
|
||||
// or attributes the session to root, and neither has a login keychain to offer.
|
||||
func CurrentConsoleUser() (ConsoleUser, bool) {
|
||||
if err := loadConsoleUser(); err != nil {
|
||||
log.Infof("console user lookup unavailable: %v", err)
|
||||
log.Debugf("console user lookup unavailable: %v", err)
|
||||
return ConsoleUser{}, false
|
||||
}
|
||||
|
||||
var uid, gid uint32
|
||||
name := scDynamicStoreCopyConsoleUser(0, &uid, &gid)
|
||||
if name == 0 {
|
||||
log.Info("no console user is logged in, no login keychain is reachable")
|
||||
log.Debug("no console user is logged in, no login keychain is reachable")
|
||||
return ConsoleUser{}, false
|
||||
}
|
||||
defer cfRelease(name)
|
||||
|
||||
user := ConsoleUser{Name: cfString(name), UID: uid, GID: gid}
|
||||
if !user.hasDesktop() {
|
||||
log.Infof("console session belongs to %q uid=%d, which is not a desktop login, no login keychain is reachable", user.Name, user.UID)
|
||||
log.Debugf("console session belongs to %q uid=%d, which is not a desktop login, no login keychain is reachable", user.Name, user.UID)
|
||||
return ConsoleUser{}, false
|
||||
}
|
||||
return user, true
|
||||
|
||||
@@ -46,12 +46,12 @@ func CurrentDesktopUser() (DesktopUser, bool) {
|
||||
if user, ok := desktopUser(session); ok {
|
||||
return user, true
|
||||
}
|
||||
log.Infof("console session %d has nobody signed in, looking for an active remote session", session)
|
||||
log.Debugf("console session %d has nobody signed in, looking for an active remote session", session)
|
||||
}
|
||||
|
||||
sessions, err := activeSessions()
|
||||
if err != nil {
|
||||
log.Infof("cannot enumerate terminal sessions: %v", err)
|
||||
log.Debugf("cannot enumerate terminal sessions: %v", err)
|
||||
return DesktopUser{}, false
|
||||
}
|
||||
for _, session := range sessions {
|
||||
@@ -60,7 +60,7 @@ func CurrentDesktopUser() (DesktopUser, bool) {
|
||||
}
|
||||
}
|
||||
|
||||
log.Info("no interactive session is signed in, no user certificate store is reachable")
|
||||
log.Debug("no interactive session is signed in, no user certificate store is reachable")
|
||||
return DesktopUser{}, false
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ func desktopUser(session uint32) (DesktopUser, bool) {
|
||||
|
||||
name, err := tokenAccount(token)
|
||||
if err != nil {
|
||||
log.Infof("session %d token has no readable account: %v", session, err)
|
||||
log.Debugf("session %d token has no readable account: %v", session, err)
|
||||
if closeErr := token.Close(); closeErr != nil {
|
||||
log.Debugf("failed closing session token: %v", closeErr)
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ func runHelper(ctx context.Context, store Store, in io.Reader, out io.Writer) er
|
||||
if len(challenges) > 0 {
|
||||
proofs = CollectChallenges(ctx, store, challenges, req.PeerKey)
|
||||
}
|
||||
log.Infof("certificate posture helper: answering %d challenges with %d proofs", len(challenges), len(proofs))
|
||||
log.Debugf("certificate posture helper: answering %d challenges with %d proofs", len(challenges), len(proofs))
|
||||
|
||||
if err := json.NewEncoder(out).Encode(HelperResponse{Proofs: proofs}); err != nil {
|
||||
return fmt.Errorf("encode helper response: %w", err)
|
||||
|
||||
@@ -56,8 +56,8 @@ func mergeProofs(device, user []certposture.Proof) []certposture.Proof {
|
||||
func logUserProof(proof certposture.Proof) {
|
||||
leaf, err := x509.ParseCertificate(proof.Chain[0])
|
||||
if err != nil {
|
||||
log.Infof("certificate posture: user proof carries an unparsable leaf: %v", err)
|
||||
log.Debugf("certificate posture: user proof carries an unparsable leaf: %v", err)
|
||||
return
|
||||
}
|
||||
log.Infof("certificate posture: signed-in user proved %q issued by %q", leaf.Subject, leaf.Issuer)
|
||||
log.Debugf("certificate posture: signed-in user proved %q issued by %q", leaf.Subject, leaf.Issuer)
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ func (s *KeychainStore) Candidates(_ context.Context) ([]Candidate, error) {
|
||||
log.Warnf("skipping keychain identity: %v", err)
|
||||
return false, nil
|
||||
}
|
||||
log.Infof("keychain identity: subject=%q issuer=%q serial=%s expires=%s", cert.Subject, cert.Issuer, cert.SerialNumber, cert.NotAfter)
|
||||
log.Debugf("keychain identity: subject=%q issuer=%q serial=%s expires=%s", cert.Subject, cert.Issuer, cert.SerialNumber, cert.NotAfter)
|
||||
leaves = append(leaves, cert)
|
||||
return false, nil
|
||||
})
|
||||
@@ -89,17 +89,17 @@ func (s *KeychainStore) Candidates(_ context.Context) ([]Candidate, error) {
|
||||
return nil, err
|
||||
}
|
||||
if len(leaves) == 0 {
|
||||
log.Infof("keychain search list holds no identities usable for certificate posture, but %d readable certificates: an identity needs its private key in the same keychain", len(pool))
|
||||
log.Debugf("keychain search list holds no identities usable for certificate posture, but %d readable certificates: an identity needs its private key in the same keychain", len(pool))
|
||||
return nil, nil
|
||||
}
|
||||
log.Infof("keychain search list holds %d identities and %d certificates for chain building", len(leaves), len(pool))
|
||||
log.Debugf("keychain search list holds %d identities and %d certificates for chain building", len(leaves), len(pool))
|
||||
|
||||
candidates := make([]Candidate, 0, len(leaves))
|
||||
for _, leaf := range leaves {
|
||||
chain := buildChain(leaf, pool)
|
||||
log.Infof("keychain candidate %q issued by %q built a chain of %d certificates", leaf.Subject, leaf.Issuer, len(chain))
|
||||
log.Debugf("keychain candidate %q issued by %q built a chain of %d certificates", leaf.Subject, leaf.Issuer, len(chain))
|
||||
if len(chain) == 1 && leaf.CheckSignatureFrom(leaf) != nil {
|
||||
log.Infof("keychain candidate %q has no issuer in the keychain, its proof carries the leaf alone and only verifies if the challenge supplies %q", leaf.Subject, leaf.Issuer)
|
||||
log.Debugf("keychain candidate %q has no issuer in the keychain, its proof carries the leaf alone and only verifies if the challenge supplies %q", leaf.Subject, leaf.Issuer)
|
||||
}
|
||||
candidates = append(candidates, Candidate{Chain: chain, Signer: &keychainSigner{leaf: leaf}})
|
||||
}
|
||||
@@ -121,7 +121,7 @@ func (s *keychainSigner) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Infof("signing certificate posture challenge with keychain key of %q", s.leaf.Subject)
|
||||
log.Debugf("signing certificate posture challenge with keychain key of %q", s.leaf.Subject)
|
||||
|
||||
algorithm := keychainAlgorithm(scheme)
|
||||
var signature []byte
|
||||
@@ -138,7 +138,7 @@ func (s *keychainSigner) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts
|
||||
if signature == nil {
|
||||
return nil, errors.New("certificate is no longer in the keychain")
|
||||
}
|
||||
log.Infof("keychain signed certificate posture challenge for %q, %d bytes", s.leaf.Subject, len(signature))
|
||||
log.Debugf("keychain signed certificate posture challenge for %q, %d bytes", s.leaf.Subject, len(signature))
|
||||
return signature, nil
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ func keychainCertificates() ([]*x509.Certificate, error) {
|
||||
unparsable++
|
||||
return false, nil
|
||||
})
|
||||
log.Infof("keychain holds %d parsable certificates, %d unparsable", len(certs), unparsable)
|
||||
log.Debugf("keychain holds %d parsable certificates, %d unparsable", len(certs), unparsable)
|
||||
return certs, err
|
||||
}
|
||||
|
||||
@@ -210,16 +210,16 @@ func eachMatching(class uintptr, name string, fn func(item uintptr) (bool, error
|
||||
switch status := secItemCopyMatching(query, &items); status {
|
||||
case 0:
|
||||
case errSecItemNotFound:
|
||||
log.Infof("keychain %s query returned errSecItemNotFound (%d): the search list holds no item of this class", name, errSecItemNotFound)
|
||||
log.Debugf("keychain %s query returned errSecItemNotFound (%d): the search list holds no item of this class", name, errSecItemNotFound)
|
||||
return nil
|
||||
default:
|
||||
log.Infof("keychain %s query returned OSStatus %d", name, status)
|
||||
log.Debugf("keychain %s query returned OSStatus %d", name, status)
|
||||
return fmt.Errorf("SecItemCopyMatching: %d", status)
|
||||
}
|
||||
defer cfRelease(items)
|
||||
|
||||
n := cfArrayGetCount(items)
|
||||
log.Infof("keychain %s query returned %d items", name, n)
|
||||
log.Debugf("keychain %s query returned %d items", name, n)
|
||||
for i := 0; i < n; i++ {
|
||||
if stop, err := fn(cfArrayGetValueAtIndex(items, i)); stop || err != nil {
|
||||
return err
|
||||
@@ -241,10 +241,10 @@ func dataBytes(data uintptr) []byte {
|
||||
func loadKeychain() error {
|
||||
keychainOnce.Do(func() {
|
||||
if keychainErr = resolveKeychain(); keychainErr != nil {
|
||||
log.Infof("macOS keychain unavailable for certificate posture: %v", keychainErr)
|
||||
log.Debugf("macOS keychain unavailable for certificate posture: %v", keychainErr)
|
||||
return
|
||||
}
|
||||
log.Infof("macOS Security framework loaded for certificate posture, running as uid=%d euid=%d", os.Getuid(), os.Geteuid())
|
||||
log.Debugf("macOS Security framework loaded for certificate posture, running as uid=%d euid=%d", os.Getuid(), os.Geteuid())
|
||||
logSearchList()
|
||||
})
|
||||
return keychainErr
|
||||
@@ -254,21 +254,21 @@ func loadKeychain() error {
|
||||
// System keychain and System Roots, never a user's login keychain.
|
||||
func logSearchList() {
|
||||
if secKeychainCopySearchList == nil || secKeychainGetPath == nil {
|
||||
log.Info("keychain search list diagnostics unavailable on this macOS version")
|
||||
log.Debug("keychain search list diagnostics unavailable on this macOS version")
|
||||
return
|
||||
}
|
||||
|
||||
var list uintptr
|
||||
if status := secKeychainCopySearchList(&list); status != 0 {
|
||||
log.Infof("SecKeychainCopySearchList returned OSStatus %d", status)
|
||||
log.Debugf("SecKeychainCopySearchList returned OSStatus %d", status)
|
||||
return
|
||||
}
|
||||
defer cfRelease(list)
|
||||
|
||||
n := cfArrayGetCount(list)
|
||||
log.Infof("keychain search list contains %d keychains", n)
|
||||
log.Debugf("keychain search list contains %d keychains", n)
|
||||
for i := 0; i < n; i++ {
|
||||
log.Infof("keychain search list[%d]: %s", i, keychainPath(cfArrayGetValueAtIndex(list, i)))
|
||||
log.Debugf("keychain search list[%d]: %s", i, keychainPath(cfArrayGetValueAtIndex(list, i)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,7 +356,7 @@ func resolveKeychain() error {
|
||||
func resolveOptional(lib uintptr, name string, ptr any) {
|
||||
symbol, err := purego.Dlsym(lib, name)
|
||||
if err != nil {
|
||||
log.Infof("keychain diagnostics: %s unavailable: %v", name, err)
|
||||
log.Debugf("keychain diagnostics: %s unavailable: %v", name, err)
|
||||
return
|
||||
}
|
||||
purego.RegisterFunc(ptr, symbol)
|
||||
|
||||
@@ -72,7 +72,7 @@ func (s *PKCS11Store) Candidates(_ context.Context) ([]Candidate, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Infof("%s holds %d certificates, %d certificate files without a key wait for its keys", s, len(certs), len(fileChains))
|
||||
log.Debugf("%s holds %d certificates, %d certificate files without a key wait for its keys", s, len(certs), len(fileChains))
|
||||
|
||||
pool := make([]*x509.Certificate, 0, len(certs))
|
||||
for _, cert := range certs {
|
||||
@@ -85,7 +85,7 @@ func (s *PKCS11Store) Candidates(_ context.Context) ([]Candidate, error) {
|
||||
var candidates []Candidate
|
||||
for _, cert := range certs {
|
||||
if _, err := privateKey(session, cert.id); err != nil {
|
||||
log.Infof("%s certificate %q has no usable private key: %v", s, cert.cert.Subject, err)
|
||||
log.Debugf("%s certificate %q has no usable private key: %v", s, cert.cert.Subject, err)
|
||||
continue
|
||||
}
|
||||
candidates = append(candidates, s.candidate(cert.cert, cert.id, pool))
|
||||
@@ -112,7 +112,7 @@ func (s *PKCS11Store) Candidates(_ context.Context) ([]Candidate, error) {
|
||||
|
||||
func (s *PKCS11Store) candidate(leaf *x509.Certificate, id []byte, pool []*x509.Certificate) Candidate {
|
||||
chain := buildChain(leaf, pool)
|
||||
log.Infof("%s candidate %q issued by %q built a chain of %d certificates", s, leaf.Subject, leaf.Issuer, len(chain))
|
||||
log.Debugf("%s candidate %q issued by %q built a chain of %d certificates", s, leaf.Subject, leaf.Issuer, len(chain))
|
||||
return Candidate{Chain: chain, Signer: &pkcs11Signer{store: s, leaf: leaf, id: id}}
|
||||
}
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ func (s *SystemStore) Candidates(_ context.Context) ([]Candidate, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
log.Infof("certificate store %s holds %d personal certificates and %d intermediates", s, len(leaves), len(intermediates))
|
||||
log.Debugf("certificate store %s holds %d personal certificates and %d intermediates", s, len(leaves), len(intermediates))
|
||||
if len(leaves) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
@@ -87,7 +87,7 @@ func (s *SystemStore) Candidates(_ context.Context) ([]Candidate, error) {
|
||||
candidates := make([]Candidate, 0, len(leaves))
|
||||
for _, leaf := range leaves {
|
||||
chain := buildChain(leaf, pool)
|
||||
log.Infof("certificate store %s candidate %q issued by %q built a chain of %d certificates", s, leaf.Subject, leaf.Issuer, len(chain))
|
||||
log.Debugf("certificate store %s candidate %q issued by %q built a chain of %d certificates", s, leaf.Subject, leaf.Issuer, len(chain))
|
||||
candidates = append(candidates, Candidate{Chain: chain, Signer: &systemStoreSigner{leaf: leaf, location: s.location}})
|
||||
}
|
||||
return candidates, nil
|
||||
|
||||
Reference in New Issue
Block a user