func authenticate()

in pam_ussh.go [70:202]


func authenticate(w io.Writer, uid int, username, ca string, principals map[string]struct{}) AuthResult {
	authSock := os.Getenv("SSH_AUTH_SOCK")
	if authSock == "" {
		fmt.Fprint(w, "No SSH_AUTH_SOCK")
		return AuthError
	}

	origEUID := os.Geteuid()
	if os.Getuid() != origEUID || origEUID == 0 {
		// Note: this only sets the euid and doesn't do anything with the egid.
		// That should be fine for most cases, but it's worth calling out.
		if !seteuid(uid) {
			pamLog("error dropping privs from %d to %d", origEUID, uid)
			return AuthError
		}
		defer func() {
			if !seteuid(origEUID) {
				pamLog("error resetting uid to %d", origEUID)
			}
		}()
	}

	agentSock, err := net.Dial("unix", authSock)
	if err != nil {
		fmt.Fprintf(w, "error connecting to %s: %v\n", authSock, err)
		// if we're here, we probably can't stat the socket to get the owner uid
		// to decorate the logs, but we might be able to read the parent directory.
		ownerUID := ownerUID(path.Dir(authSock))
		pamLog("error opening auth sock (sock owner: %d/%s) by (caller: %d/%s)",
			ownerUID, getUsername(ownerUID), os.Getuid(), username)
		return AuthError
	}

	a := agent.NewClient(agentSock)
	keys, err := a.List()
	if err != nil {
		pamLog("Error listing keys: %v", err)
		return AuthError
	}

	if len(keys) == 0 {
		pamLog("No certs loaded.\n")
		return AuthError
	}

	caBytes, err := ioutil.ReadFile(ca)
	if err != nil {
		pamLog("error reading ca: %v\n", err)
		return AuthError
	}

	var caPubkeys []ssh.PublicKey
	in := caBytes
	for {
		pubKey, _, _, rest, err := ssh.ParseAuthorizedKey(in)
		if err != nil {
			pamLog("skipping bad public key: %v", err)
		} else {
			caPubkeys = append(caPubkeys, pubKey)
		}
		if len(rest) == 0 {
			break
		}
		in = rest
	}

	c := &ssh.CertChecker{
		IsUserAuthority: func(auth ssh.PublicKey) bool {
			for _, k := range caPubkeys {
				if bytes.Equal(auth.Marshal(), k.Marshal()) {
					return true
				}
			}
			return false
		},
	}

	for idx := range keys {
		pubKey, err := ssh.ParsePublicKey(keys[idx].Marshal())
		if err != nil {
			continue
		}

		cert, ok := pubKey.(*ssh.Certificate)
		if !ok {
			continue
		}

		if err := c.CheckCert(username, cert); err != nil {
			continue
		}

		if !c.IsUserAuthority(cert.SignatureKey) {
			pamLog("certificate signed by unrecognized authority")
			continue
		}

		// for the ssh agent to sign some data validating that they do in fact
		// have the private key
		randBytes := make([]byte, 32)
		if _, err := rand.Read(randBytes); err != nil {
			pamLog("Error grabbing random bytes: %v\n", err)
			return AuthError
		}

		signedData, err := a.Sign(pubKey, randBytes)
		if err != nil {
			pamLog("error signing data: %v\n", err)
			return AuthError
		}

		if err := pubKey.Verify(randBytes, signedData); err != nil {
			pamLog("signature verification failed: %v\n", err)
			return AuthError
		}

		if len(principals) == 0 {
			pamLog("Authentication succeeded for %q (cert %q, %d)",
				username, cert.ValidPrincipals[0], cert.Serial)
			return AuthSuccess
		}

		for _, p := range cert.ValidPrincipals {
			if _, ok := principals[p]; ok {
				pamLog("Authentication succeded for %s. Matched principal %s, cert %d",
					cert.ValidPrincipals[0], p, cert.Serial)
				return AuthSuccess
			}
		}
	}
	pamLog("no valid certs found")
	return AuthError
}