Code Monkey home page Code Monkey logo

glome's Introduction

Generic Low Overhead Message Exchange (GLOME)

GLOME Login is a challenge-response authentication mechanism. It resembles one-time authorization codes (aka OTPs) but is different from [HOTP] and [TOTP] in the following ways:

  • It is stateless (unlike [HOTP]).
  • It does not depend on time (unlike [TOTP]).
  • It does not require predefined secret sharing (unlike [HOTP] and [TOTP]).

These properties make it a good choice for low dependency environments (e.g., devices with no persistent storage a real-time clock). It can be also useful for managing access to a large fleet of hosts where synchronising state or sharing predefined secrets can be a challenge.

GLOME Login can be easily integrated with existing systems through PAM (libglome) or through the login(1) wrapper (glome-login).

GLOME Login protocol is is built on top of the Generic Low Overhead Message Exchange (GLOME) protocol.

[TOTP]: https://www.rfc-editor.org/rfc/rfc6238 [HOTP]: https://www.rfc-editor.org/rfc/rfc4226

How does it work?

Let's imagine the following scenario:

Alice is a system engineer who got paged to investigate an unresponsive machine that happens to be located far away. She calls Bob, a datacenter technican with physical access to the machine.

Alice is authorized to access the machine but has no connectivity. Bob faces the opposite problem, he can access the machine's serial port but does not have credentials to log in.

Alice is able to use GLOME Login to grant Bob one-time access to the machine. First, Bob connects to the machine over serial port and types root on the login prompt. He is then provided with a challenge that he forwards to Alice. The challenge contains information about the identity of accessed host and the requested action (i.e., root shell access). Alice verifies that the request is legitimate (e.g., the accessed host is indeed the one she's trying to diagnose), and uses the glome CLI to generate an authorization code. She forwards that authorization code to Bob who provides it as a challenge response.

The authorization succeeds and Bob is able to run diagnostic commands and share the results with Alice.

Getting started

Installation on the client host

These steps should be followed on the host you are planning to use to generate authorization codes (e.g., a laptop).

  1. Follow build to build the glome CLI binary.
  2. Generate a key pair using the glome command. Note that if the glome command is not in your $PATH, you might need to provide a full path to the binary.
$ glome genkey | tee glome-private.key | glome pubkey | tee glome-public.key | xxd -c 32 -p
4242424242424242424242424242424242424242424242424242424242424242

The output of that command is the approver public key that will be used to configure the target host.

Installation on the target host

  1. Follow instructions to configure your host to use PAM module (recommended) or glome-login.
  2. Edit the configuration file (by default located at /etc/glome/config) and replace the key value with the approver public key generated in the previous section.
$ cat /etc/glome/config
key=4242424242424242424242424242424242424242424242424242424242424242
key-version=1

Usage

Try to log in to the target host. You should see the prompt with the challenge:

GLOME: v1/AU7U7GiFDG-ITgOh8K_ND9u41S3S-joGp7MAdhIp_rQt/myhost/shell/root/
Password:

Use the glome CLI on the client host to obtain an authorization code:

$ glome --key glome-private.key login
v1/AU7U7GiFDG-ITgOh8K_ND9u41S3S-joGp7MAdhIp_rQt/myhost/shell/root/Tm90aGluZyB0byBzZWUgaGVyZSwgbW92ZSBhbG9uZy4K

Provide the generated authcode as a response to the challenge.

Repository

This repository consists of a number of components of the GLOME ecosystem.

Documentation:

Core libraries:

Binaries:

  • glome Command-line interface for GLOME
  • glome-login Replacement of login(1) implementing GLOME Login protocol

Building

Building the GLOME library requires

  • Compiler conforming to C99 (e.g. gcc, clang)
  • Meson >=0.49.2
  • OpenSSL headers >=1.1.1
  • glib-2.0 (for glome-login as well as tests)
  • libpam (for PAM module)

Alternatively, on systems with Nix, you can simply run nix-shell in the root directory of this repository.

Instructions

GLOME is built using Meson. First, initialize the Meson build directory. You only have to do this once per Meson configuration.

$ meson build

NOTE: You can customize the installation target by passing the --prefix flag.

Build the shared library libglome.so and the command line utility glome inside the build root ./build.

$ ninja -C build

Now run the tests.

$ meson test -C build

Install both the binary and the library into the configured prefix (the default prefix is /usr/local/, which will require admin privileges).

$ meson install -C build

Disclaimer

This is not an officially supported Google product.

glome's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

glome's Issues

glome-login test vector 2 does not use top 7 bits of key ID

The C implementation of glome-login used & 0x7f to mask the top bit of the service key ID and ensure it fits into 7 bits. The same logic was reused for calculating the key ID from the top byte of the service public key:

  if (service_key_id == 0) {
    // If no key ID was specified, send the first key byte as the ID.
    handshake[0] = service_key[0] & 0x7f;
  } else {
    handshake[0] = service_key_id & 0x7f;
  }

This is broken and sadly has been replicated into test vector 2 as well. To get the top 7 bits of the key ID the correct calculation would be >> 1 and thus 0xd1 >> 1 = 0x68 instead of 0xd1 & 0x7f = 0x51.

Support more fleet-wide settings in the config file

It would be convenient if we could set a couple of options that are usually constant in a given deployment environment with the config file. That would allow sharing a glome-login binary between environments, and customizing each environment with the config file only. Things that I can think of:

  • hostid-type (hostid would still be obtained from gethostname(2))
  • syslog config
  • timeouts and sleeps
  • minimum tag length

Clarify glome-login protocol issues

Let's use this as an umbrella issue for clarifications that are needed in the glome-login protocol doc.

First off: Make sure we cover how URLs are supposed to be escaped in the protocol documentation.

golang ParseURLResponse function does not handle URLs correctly

The function ParseURLResponse does not accept URLs, only paths. Providing a URL as input does not fail, but produces unexpected results.

  • The function is used correctly in server.go, but the naming and documentation is misleading.
  • The HandshakeInfo seems to be computed correctly.
  • The Message is wrong.

Example code with output:

package main

import (
	"fmt"
	"log"

	"github.com/google/glome/go/glome"
	"github.com/google/glome/go/login"
)

func main() {
	srv := login.Server{KeyFetcher: func(_ uint8) (*glome.PrivateKey, error) {
		var key glome.PrivateKey
		key[5] = 1
		return &key, nil
	}}
	resp, err := srv.ParseURLResponse("https://glome.example.com/v1/UYcvQ1u4uJ0OOtYqouURB07hleHDnvaogAFBi-ZW48N2/serial-number:123/reboot/")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("login.Message%+v\n", resp.Msg)
}
login.Message{HostIDType:https HostID: Action:/glome.example.com/v1/UYcvQ1u4uJ0OOtYqouURB07hleHDnvaogAFBi-ZW48N2/serial-number:123/reboot}

Add Go GLOME config file parsing

We have an internal user of GLOME that's written their own config parser. Let's provide an in-tree config parser in Go, so we can include it in test suites publically and keep it updated in lockstep with the C one.

PAM module arguments naming is inconsistent with the config

It would be great if PAM module arguments naming was consistent with the config (and flags in the future once glome-login suports long flags).

Examples of inconsistency:

  • service_key (PAM) vs key (config)
  • service_key_version (PAM) vs key-version (config)
  • url_prefix (PAM) vs url-prefix (config)

Personally, I like the config naming better. It's shorter and uses dashes instead of underscores.

Build fails on NixOS

See this action: https://github.com/google/glome/actions/runs/3758587828/jobs/6387107347. It seems like the issue is that below warning is treated as an error, but I don't understand why that changed since that action was merged.

/nix/store/mmmjp0xcmr0dm307jv1l34hvi95z6d8s-glibc-2.35-224-dev/include/features.h:412:4: error: #warning _FORTIFY_SOURCE requires compiling with optimization (-O) [-Werror=cpp]
  412 | #  warning _FORTIFY_SOURCE requires compiling with optimization (-O)
      |    ^~~~~~~
cc1: all warnings being treated as errors

CLI should be tested according to specification

We only test that a tag produced by the CLI is in turn correctly verified by the CLI - this fails to detect symmetric breakage, e.g. due to invalid parsing / reading. There should be a suite that verifies the test vectors from the specification.

glome-login refers to a mysterious "embedded" service key

In glome-login --help I spotted the following:

 -k KEY    use KEY as the hex-encoded service key (defaults to the embedded key)

I can't seem to find any reference to what this embedded key is and where it lives, and from looking at the source code I suspect it might not exist. Could you clarify the documentation and/or remove this?

"meson install" tries to install an example config with a default service key

When running "meson install", the build system installs example.cfg as the default configuration. Since example.cfg is a working config file with a hardcoded key, this seems like a dangerous behavior.

Luckily, it happens that a bug makes this harmless right now: meson installs to ${sysconfdir}/config while glome-login attempts to look up the config in ${sysconfdir}/glome/config. I suspect this is however not deliberate :-)

Improve documentation of `glome.h`

Instead of single sentences, the public functions should document all their parameters, especially wrt ownership, and describe the scenario where the function is appropriate.

GLOME Login assumes that challenge is an URL

Currently GLOME Login prompts assume that the user is obtaining authcodes by following an URL. While this might be true in some environments, most individual users are going to simply use glome CLI to generate responses and they might be confused by the current UI.

Contexts where it is assumed that the challenge is an URL:

"\n -u URL use given URL prefix"

} else if (strcmp(key, "url-prefix") == 0) {

} else if (!strncmp(argv[i], "url_prefix=", 11)) {

prompting the user for the password, it generates an URL that points at the
authorization server and contains the GLOME handshake information and the action
requested by the operator. The operator follows that URL and upon successful

The following one doesn't say that the challenge is an URL but perhaps the wording here could be improved:

config, NULL, "Obtain the one-time authorization code from:\n%s%s",

Increase portability of GLOME build

The build process contains a couple of minor choices that prevent porting onto non-glibc systems. My use case is Alpine, but the situation is probably similar on MacOS or *BSD.

  • Bash shell is assumed to be available, thus bashisms in scripts.
  • Non-POSIX utilities used: mktemp, realpath.
  • glibc-only headers are used (unnecessarily :) ).

MVP: Login PAM module plus signing CLI

We should actually go and design how glome-login is supposed to be used - with integration into Debian/Ubuntu as an example. I'd suggest the following:

  • Users should be able to install a libpam-glome package and the distro scripts would add pam_glome to at least the login PAM auth chain, if not common-auth.
  • This would do nothing (no failure or error message, PAM_AUTHINFO_UNAVAIL?) unless /etc/glome/config is found and contains both a service key and a URL prefix - or alternative both are passed via the arguments to the PAM module.
  • The PAM module should use pam_get_authtok to get the tag, which honors try_first_pass. That way we can stack modules properly.
  • pam_glome should then sort before pam_unix (in Debian/Ubuntu-speak its priority for pam-auth-update needs to be higher than unix's 256 - pam_unix would then automatically gain try_first_pass). This would print the GLOME URL and a Password: prompt that would accept the tag. If the tag does not validate, PAM would continue with pam_unix and check the token as a password.
  • This would of course namespace collide tags and passwords, but I think that's an acceptable tradeoff here. Users who do not want password validation can deactivate the password in /etc/shadow and pam_unix will DTRT.
  • My understanding is that such a setup would work with regular terminal-like setups and even SSH - although very likely not with screensavers as the URL would not be displayed properly in that case. Note that the default timeout for login on Debian/Ubuntu is 60s - which is a little short for our protocol. We might want to document raising this through /etc/login.defs.
  • We should have a minimal CLI that actually works with the glome-login protocol rather than just GLOME. The current CLI is kinda weird - it does not even generate the hex keys necessary for glome-login, so you first need to convert them away from binary.
  • We could go with glome login sign/tag - or glome-login sign, I don't really care. But it also turns out that we do not have URL decomposition in C yet, which would be somewhat useful to feed URLs into. Basically I think it'd be great to have a CLI that takes the private key file as an argument and parses everything from the /v1/ to the end and generates the appropriate tag to login with. Additionally there should be commands alike wg genkey and wg pubkey that DTRT. Then we'd be at the same technical level as Wireguard, where you still need to put those keys into the appropriate places in the config file - although we'd still ship an example config with the keys commented out. Technically this could also be written in a language different from C. I think from a distro point of view I'd weakly prefer it to be Python or C rather than Go.
  • We might need to decide if glome-login is worth keeping for more minimal environments without PAM.

cc @burgerdev @bluecmd @vvidic @l9i

Reboot action is not authenticated

Starting glome-login with the reboot username immediately reboots the machine without asking for any authentication.

Not sure if this is expected or not?

More user-friendly landing README

User friendliness of the main README should be improved before the first release:

  • Provide tl;dr that explain the goal of the project
  • Illustrate how GLOME Login could be used (e.g., with a hypothetical scenario)
  • Add instructions on how to use GLOME Login

README for go code

Both go/login and go/login/server would ejoy having a README.md file that guide the user through the code.

Key material should have a consistent and safe format

The private keys produced by glome genkey (and the corresponding public keys from glome pubkey) are x25519 keys, i.e. 32 raw octets.

Key Exchange

Dealing with GLOME keys is inconvenient: transferring a public key to another system requires either a direct file transfer (e.g. scp) or an intermediate encoding into the printable range (e.g. base64). SSH keys, for comparison, are PEM encoded and can be easily copied or included in an email. Furthermore, given only the key file it is impossible to determine its nature, which could lead to accidental confusion of private and public keys. In the best case, you just cannot determine whether the 32B file in your home directory created two years ago is a GLOME key or something else.

Encoding Logic

All keys in the spec are hex-encoded, as are the keys in tests and for glome-login. The lack of encoding in the GLOME library causes a proliferation of encoding logic elsewhere, as can be seen by the definition of a decode_hex in glome_test.c, cli/commands.c and login/ui.c. Since parsing and deserialization logic is a common source of security vulnerabilities, it would be better to have one central piece of logic for dealing with encoding that is well tested.

Protocol Variants

The keys do not specify which protocol variant they are to be used with. If the two parties disagree on the variant to be used we would at least expect mismatching tags, while a deliberately introduced confusion by a person-in-the-middle could ostensibly lead to more severe outcomes.

glome-login leaving an extra newline in the input buffer before returning?

A tiny nit I've had with glome-login for a while (this behavior has been here for 1+ year): after I enter my authentication code and I get logged in, it seems like there is a spurious newline still in the input buffer which causes my shell to give me two prompts:

smol login: root
Obtain the one-time authorization code from:
<snip>
> <snip>
Authorization code: OK

[root@smol:~]# 

[root@smol:~]# 

glome-login config file cannot be 'special'

The range of acceptable config files for g_key_file_load_from_file is limited to 'regular' files (as determined by S_ISREG), unfortunately excluding a bunch of legitimate config sources:

$ ./build/login/glome-login -c /dev/null root
ERROR: config file could not be read: Not a regular file

Error: parse-config
$ ./build/login/glome-login -c <(echo -e "[service]\nkey = fee1dead...") root
ERROR: config file could not be read: Not a regular file

Error: parse-config

CLI should handle tags as base64 instead of hex

It's slightly confusing that the CLI prints and verifies tags in hex format, while the tag is exchanged base64-encoded in the login protocol. base64 has arguably better utility support and would allow using the cli as client without re-encoding, so I propose changing the output of glome tag to base64.

Enhance HTML output.

As pointed out by @burgerdev, Key list should be HTML output with a <table>, or at least configurable to be raw text or html using the Accept header for it, rather than a query parameter.

glome-cli demo outputs spurious errors when using even-sized key names

The glome-cli demo conveniently uses Alice and Bob, respectively 5 and 3 characters. Replacing Alice with test ends up showing some spurious errors due to trying to parse test as a hex key:

$ glome-cli test
ERROR while parsing byte 0 ('te') as hex
1f8b8245ddbe65db2e593683fbc4596d0859cbdd2885a20708478880c57c8e4e

Things still work, but it's confusing.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.