control/controlclient: return correct certificate

When searching for the matching client identity, the returned
certificate chain was accidentally set to that of the last identity
returned by the certificate store instead of the one corresponding to
the selected identity.

Also, add some extra error checking for invalid certificate chains, just
in case.

Signed-off-by: Adrian Dewhurst <adrian@tailscale.com>
pull/1670/head
Adrian Dewhurst 3 years ago committed by Adrian Dewhurst
parent 799973a68d
commit 3f456ba2e7

@ -51,40 +51,61 @@ var (
errBadRequest = errors.New("malformed request") errBadRequest = errors.New("malformed request")
) )
// findIdentity locates an identity from the Windows or Darwin certificate func isSupportedCertificate(cert *x509.Certificate) bool {
// store. It returns the first certificate with a matching Subject anywhere in return cert.PublicKeyAlgorithm == x509.RSA
// its certificate chain, so it is possible to search for the leaf certificate, }
// intermediate CA or root CA. If err is nil then the returned identity will
// never be nil (if no identity is found, the error errNoMatch will be func isSubjectInChain(subject string, chain []*x509.Certificate) bool {
// returned). If an identity is returned then its certificate chain is also if len(chain) == 0 || chain[0] == nil {
// returned. return false
func findIdentity(subject string, st certstore.Store) (certstore.Identity, []*x509.Certificate, error) { }
ids, err := st.Identities()
if err != nil { for _, c := range chain {
return nil, nil, err if c == nil {
continue
}
if c.Subject.String() == subject {
return true
}
} }
var selected certstore.Identity return false
var chain []*x509.Certificate }
func selectIdentityFromSlice(subject string, ids []certstore.Identity) (certstore.Identity, []*x509.Certificate) {
for _, id := range ids { for _, id := range ids {
chain, err = id.CertificateChain() chain, err := id.CertificateChain()
if err != nil { if err != nil {
continue continue
} }
if chain[0].PublicKeyAlgorithm != x509.RSA { if !isSupportedCertificate(chain[0]) {
continue continue
} }
for _, c := range chain { if isSubjectInChain(subject, chain) {
if c.Subject.String() == subject { return id, chain
selected = id
break
}
} }
} }
return nil, nil
}
// findIdentity locates an identity from the Windows or Darwin certificate
// store. It returns the first certificate with a matching Subject anywhere in
// its certificate chain, so it is possible to search for the leaf certificate,
// intermediate CA or root CA. If err is nil then the returned identity will
// never be nil (if no identity is found, the error errNoMatch will be
// returned). If an identity is returned then its certificate chain is also
// returned.
func findIdentity(subject string, st certstore.Store) (certstore.Identity, []*x509.Certificate, error) {
ids, err := st.Identities()
if err != nil {
return nil, nil, err
}
selected, chain := selectIdentityFromSlice(subject, ids)
for _, id := range ids { for _, id := range ids {
if id != selected { if id != selected {
id.Close() id.Close()

Loading…
Cancel
Save