github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/controller/internal/enforcer/applicationproxy/tcp/verifier/verifier.go (about) 1 package verifier 2 3 import ( 4 "crypto/x509" 5 "encoding/asn1" 6 "encoding/json" 7 "fmt" 8 "sync" 9 10 "go.aporeto.io/enforcerd/trireme-lib/collector" 11 "go.aporeto.io/enforcerd/trireme-lib/policy" 12 ) 13 14 // aporetoASNTagsExtension holds the value of the Aporeto Tags Extension 15 var aporetoASNTagsExtension asn1.ObjectIdentifier 16 17 // aporetoPingExtension holds the value of the Aporeto Ping Extension 18 var aporetoPingExtension asn1.ObjectIdentifier 19 20 // PolicyReporter is the interface to allow looking up policies and report stats 21 type PolicyReporter interface { 22 IDLookup(remoteContoller, remotePUID string, tags *policy.TagStore) bool 23 IPLookup() bool 24 Policy(tags *policy.TagStore) (*policy.FlowPolicy, *policy.FlowPolicy) 25 ReportStats(remoteType collector.EndPointType, remoteController string, remotePUID string, mode string, report *policy.FlowPolicy, packet *policy.FlowPolicy, accept bool) 26 } 27 28 // Verifier interface defines the methods a verifier must implement 29 type Verifier interface { 30 31 // TrustCA replaces the trusted CA list. 32 TrustCAs(caPool *x509.CertPool) 33 34 // VerifyPeerCertificate verifies if this TLS connection should be admitted. 35 VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate, policy PolicyReporter, mustHaveClientIDCert bool) error 36 } 37 38 // verifier implements the Verifier interface 39 type verifier struct { 40 sync.RWMutex 41 // trustedCAs stores the list of certs to be trusted 42 trustedCAPool *x509.CertPool 43 } 44 45 func init() { 46 aporetoASNTagsExtension = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 50798, 1, 1} 47 aporetoPingExtension = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 50798, 1, 4} 48 } 49 50 // New returns a new instance of Verifier 51 func New(caPool *x509.CertPool) Verifier { 52 return &verifier{ 53 trustedCAPool: caPool, 54 } 55 } 56 57 // certHasDNSOrIPSAN checks if a given name exists in a SAN for the certificate. 58 func certHasDNSOrIPSAN(san string, cert *x509.Certificate) bool { 59 60 // san found in SAN in certs 61 for _, name := range cert.DNSNames { 62 if san == name { 63 return true 64 } 65 } 66 67 for _, ip := range cert.IPAddresses { 68 if san == ip.String() { 69 return true 70 } 71 } 72 73 return false 74 } 75 76 // TrustCA replaces the trusted CA list. 77 func (v *verifier) TrustCAs(caPool *x509.CertPool) { 78 79 // Update verifier 80 v.Lock() 81 v.trustedCAPool = caPool 82 v.Unlock() 83 } 84 85 // VerifyPeerCertificate validates that policies allow mTLS between two enforcers based on 86 // aporeto-tags. If no aporeto tags are found, it applies IP based ACLs. 87 // 88 func (v *verifier) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate, pr PolicyReporter, mustHaveClientIDCert bool) error { 89 90 v.RLock() 91 opts := x509.VerifyOptions{ 92 Roots: v.trustedCAPool, 93 KeyUsages: []x509.ExtKeyUsage{ 94 x509.ExtKeyUsageServerAuth, 95 x509.ExtKeyUsageClientAuth, 96 }, 97 } 98 v.RUnlock() 99 100 // Is this an Aporeto Cert we are trusting 101 if opts.Roots != nil { 102 for _, certChain := range verifiedChains { 103 tags := []string{} 104 ping := false 105 for _, cert := range certChain { 106 for _, e := range cert.Extensions { 107 if e.Id.Equal(aporetoPingExtension) { 108 ping = true 109 continue 110 } 111 112 // If there is an Aporeto extension, get the value 113 if e.Id.Equal(aporetoASNTagsExtension) { 114 if err := json.Unmarshal(e.Value, &tags); err == nil { 115 if ping { 116 break 117 } 118 } 119 } 120 } 121 122 // No Aporeto tags 123 if len(tags) == 0 { 124 continue 125 } 126 127 rtags := policy.NewTagStoreFromSlice(tags) 128 129 // check if we have remote controller 130 rcontroller, ok := rtags.Get(policy.TagKeyController) 131 if !ok { 132 continue 133 } 134 135 // check if $identity == processingunit 136 if pu, ok := rtags.Get(policy.TagKeyIdentity); !ok && pu != policy.TagValueProcessingUnit { 137 continue 138 } 139 140 // check if we have remote puid 141 rpuid, ok := rtags.Get(policy.TagKeyID) 142 if !ok { 143 continue 144 } 145 146 if _, err := cert.Verify(opts); err != nil { 147 continue 148 } 149 150 // TODO: Check controller against verified CA 151 // fmt.Println(strings.Join(tags, " ")) 152 // if !certHasDNSOrIPSAN(controller, cert) { 153 // fmt.Println("No IP or DNS SAN", strings.Join(cert.DNSNames, " ")) 154 // continue 155 // } 156 157 // If ping is enabled in the certificate, we defer the policy lookup and the server 158 // application will never receive any packets related to ping irrespective of policy. 159 if ping { 160 return nil 161 } 162 163 if !pr.IDLookup(rcontroller, rpuid, rtags) { 164 return fmt.Errorf("ID policy lookup rejection") 165 } 166 167 return nil 168 } 169 } 170 } 171 172 if mustHaveClientIDCert { 173 return fmt.Errorf("ID lookup not performed") 174 } 175 176 if !pr.IPLookup() { 177 return fmt.Errorf("IP policy lookup rejection") 178 } 179 180 return nil 181 }