aboutsummaryrefslogtreecommitdiff
path: root/src/Program.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Program.cs')
-rw-r--r--src/Program.cs203
1 files changed, 203 insertions, 0 deletions
diff --git a/src/Program.cs b/src/Program.cs
new file mode 100644
index 0000000..230f950
--- /dev/null
+++ b/src/Program.cs
@@ -0,0 +1,203 @@
+using System;
+
+using VNLib.Utils.Logging;
+
+using static PkiAuthenticator.Statics;
+
+namespace PkiAuthenticator
+{
+ internal class Program
+ {
+ public const string JWK_EXPORT_TEMPLATE = "You may copy your JWK public key\n\n{pk}\n";
+ public const string TOKEN_PRINT_TEMPLATE = "You may copy your authentication token \n\n{tk}\n";
+ public const string YUBIKEY_PIN_ENV_VAR_NAME = "YUBIKEY_PIN";
+ public const string SOFTWARE_PASSWORD_VAR_NAME = "CERT_PASSWORD";
+ public const string PEM_EXPORT_TEMPLATE = "You may copy your public key\n\n{cert}\n";
+
+ const string HELP_MESSAGE =
+@$" VAuth Copyright (c) Vaughn Nugent
+ Usage: vauth.exe <args>
+
+ No args: Connects to the first PIV enabled YubiKey and requests slot 0x9a
+ sign a new authentication message for the default usename (cert CN),
+ prompts the user for a pin (if enabled on device) and prints the
+ signed JWT authentication token to STDOUT.
+
+ Command flags:
+
+ none/default Genereates a signed OTP (one time password) Json Web Token
+ for authentication.
+
+ -e, --export <pem> Writes the public key to the screen as a JWK, or optionally
+ PEM encoded by using the 'pem' keyword following -e.
+
+ --list-devices Lists the device information of all connected YubiKey devices.
+ (Ignores the --key flag)
+
+ -h, --help Prints this help message.
+
+ Global flags:
+
+ -u, --user <uid> The user-id (or email address) to specify during for
+ authenticating. If not specified, uses the certificates CN
+ subject value.
+
+ --software <cert file> Runs the process using a software authenticator instead of
+ a YubiKey hardware authenticator. The cert file must be a
+ a valid x509 certificate with the public key. You must also
+ set the private key file path.
+
+ --private-key <file> The path to the private key file, may be password protected.
+ This flag is only required in software mode.
+
+ --password <password?> The password string (utf8 decoded) used to decrypt the PEM
+ private key file. WARNING! You should avoid using this flag
+ unless you have cli history disabled, otherwise your password
+ may be recovered from your history file. This allows you to
+ automate the authentication process. NOTE: consider setting the
+ {SOFTWARE_PASSWORD_VAR_NAME} environment variable before starting the
+ process instead.
+
+ --key <serial> Allows you to specify the serial number (int32) of the exact
+ YubiKey to connect to if multiple keys are connected. (PIV must
+ be enabled on the device)
+
+ --pin <device pin> Allows you to specify your device's pin as an argument.
+ WARNING! You should avoid using this flag unless you have cli
+ history disabled, otherwise your pin may be recovered from your
+ history file. This allows you to automate the authentication
+ process. NOTE: consider setting the {YUBIKEY_PIN_ENV_VAR_NAME} environment
+ variable before starting the process instead.
+
+ --piv-slot <slot> The hexadecimal YubiKey PIV slot number override to use, defaults
+ to authentication (9a) slot.
+
+ -s, --silent Silences logs, only operation output is written to STDOUT. For pin-
+ required operations, a --pin flag must be set, or set the {YUBIKEY_PIN_ENV_VAR_NAME}
+ env variable. If an op error occurs, an exit code is returned.
+
+ -v, --verbose Enables verbose logging to be writtento STDOUT, is overridden
+ by silent mode, and will override -d debug mode.
+
+ -d, --debug Enables debug logging to be written to STDOUT, is overridden by
+ silent mode.
+
+ Environment Variables
+ {SOFTWARE_PASSWORD_VAR_NAME} The password used to decrypt the PEM encoded private key file in software mode
+
+ {YUBIKEY_PIN_ENV_VAR_NAME} Your secret pin used for protected yubikey operations
+
+
+ This tool was created to quickly generate short lived One-Time-Passwords (OTP) or signed
+ authentication tokens (JWT) for authenticating aginst PKI endpoints, using your YubiKey's
+ authentication slot (0x9a). You may use this tool to automate a login process by using the
+ -s flag and specifying a pin with --pin (not recommended!), or setting the {YUBIKEY_PIN_ENV_VAR_NAME}
+ environment variable.
+
+ A software, x509 certificate file backed, mode is also supported by using the --software flag.
+ The certificate file must be a PEM encoded certificate. You must also specify a PEM encoded private
+ key file using the --private-key flag. This file may be encrypted, and you must specify a --password
+ flag. You may wait for a prompt, set the {SOFTWARE_PASSWORD_VAR_NAME} environment variable, or write it after
+ the --password argument: '--password my_unsecure_password'.
+
+ Examples:
+
+ OTP:
+ vauth.exe # default cert CN usename
+ vauth.exe -u 'name@example.com' # specify username
+ vauth.exe --key 1111111 # specify hardware key serial numer
+ vauth.exe -s > token.txt # write token to a text file
+ vauth.exe --piv-slot 9C # specify a differnt PIV slot on the yubikey (in hex)
+
+ #software mode
+ vauth.exe --software 'cert.pem' --private-key 'priv.pem'
+ vauth.exe --software 'cert.pem' --private-ke 'priv.pem' --password 'mypassword'
+
+ Export public key:
+ vauth.exe --export # for JWK output
+ vauth.exe --export pem # for pem encoding
+
+ #software
+ vauth.exe --software cert.pem --export pem
+
+ List devices:
+ vauth.exe --list-devices # only supported in hardware mode
+";
+
+ static int Main(string[] args)
+ {
+ if (CliArgs.HasArg("-h") || CliArgs.HasArg("--help"))
+ {
+ Console.WriteLine(HELP_MESSAGE);
+ return 0;
+ }
+
+ Log.Information("vauth (c) 2023 Vaughn Nugent");
+
+ int exitCode = 1;
+ try
+ {
+ //Get software or hardware authenticator
+ using IAuthenticator authenticator = CliArgs.HasArg("--software") ? new SoftwareAuthenticator() : new HardwareAuthenticator();
+
+ //initialze the authenticator
+ if (authenticator.Initialize())
+ {
+ //Only continue if authenticator successfully initialized
+ if (CliArgs.HasArg("--list-devices"))
+ {
+ //List devices flag
+ exitCode = authenticator.ListDevices();
+ }
+ else if (CliArgs.HasArg("-e") || CliArgs.HasArg("--export"))
+ {
+ //Check for pem encoding flag
+ if (CliArgs.HasArg("pem"))
+ {
+ string pem = authenticator.ExportPem();
+ Log.Information(PEM_EXPORT_TEMPLATE, pem);
+ exitCode = 0;
+ }
+ else
+ {
+ //Print jwk
+ string? pupKey = authenticator.ExportJwk();
+
+ //May be null if the alg is not supported
+ if (pupKey == null)
+ {
+ Log.Error("The certificate does not use a supported algorithm");
+ }
+ else
+ {
+ //Print
+ Log.Information(JWK_EXPORT_TEMPLATE, pupKey);
+ exitCode = 0;
+ }
+ }
+ }
+ else
+ {
+ //Authenticate
+ exitCode = authenticator.GenerateOtp();
+ }
+ }
+ }
+ catch(Exception ex)
+ {
+ if (Log.IsEnabled(LogLevel.Debug))
+ {
+ Log.Error(ex);
+ }
+ else
+ {
+ Log.Error("Operation failed. Reason: {ex}", ex.Message);
+ }
+ }
+
+ Log.Information("Exiting...");
+
+ return exitCode;
+ }
+ }
+} \ No newline at end of file