feat(commands): enhance crypto generation capabilities (#2842)

This expands the functionality of the certificates and rsa commands and merges them into one command called cypto which can either use the cert or pair subcommands to generate certificates or key-pairs respectively. The rsa, ecdsa, and ed25519 subcommands exist for both the cert and pair commands. A new --ca-path argument for the cert subcommand allows Authelia to sign other certs with CA certs.

Co-authored-by: Amir Zarrinkafsh <nightah@me.com>
pull/3604/head
James Elliott 2022-06-27 18:27:57 +10:00 committed by GitHub
parent 0b5f92d9eb
commit fcac438637
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
98 changed files with 3685 additions and 1159 deletions

View File

@ -42,11 +42,11 @@ openssl rsa -in private.pem -outform PEM -pubout -out public.pem
The __Authelia__ docker container or CLI binary can be used to generate a RSA 4096 bit keypair:
```bash
docker run -u "$(id -u):$(id -g)" -v "$(pwd)":/keys authelia/authelia:latest authelia rsa generate --dir /keys
docker run -u "$(id -u):$(id -g)" -v "$(pwd)":/keys authelia/authelia:latest authelia crypto pair rsa generate --bits 4096 --directory /keys
```
```bash
authelia rsa generate --dir /path/to/keys
authelia crypto pair rsa generate --directory /path/to/keys
```
## Generating an RSA Self-Signed Certificate
@ -69,9 +69,9 @@ The __Authelia__ docker container or binary can be used to generate a RSA 4096 b
domain `example.com`:
```bash
docker run -u "$(id -u):$(id -g)" -v "$(pwd)":/keys authelia/authelia authelia certificates generate --host example.com --dir /keys
docker run -u "$(id -u):$(id -g)" -v "$(pwd)":/keys authelia/authelia authelia crypto certificate rsa generate --common-name example.com --directory /keys
```
```bash
authelia certificates generate --host example.com --dir /path/to/keys
authelia crypto certificate rsa generate --common-name example.com --directory /path/to/keys
```

View File

@ -2,7 +2,7 @@
title: "CLI"
description: ""
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
weight: 300

View File

@ -2,7 +2,7 @@
title: "authelia-gen"
description: ""
lead: ""
date: 2022-06-03T10:57:43+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:

View File

@ -2,7 +2,7 @@
title: "authelia-gen"
description: "Reference for the authelia-gen command."
lead: ""
date: 2022-06-03T10:57:43+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -28,4 +28,4 @@ Authelia's generator tooling
* [authelia-gen code](authelia-gen_code.md) - Generate code
* [authelia-gen docs](authelia-gen_docs.md) - Generate docs
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-gen all"
description: "Reference for the authelia-gen all command."
lead: ""
date: 2022-06-03T10:57:43+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -30,4 +30,4 @@ authelia-gen all [flags]
* [authelia-gen](authelia-gen.md) - Authelia's generator tooling
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-gen code"
description: "Reference for the authelia-gen code command."
lead: ""
date: 2022-06-03T10:57:43+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -31,4 +31,4 @@ authelia-gen code [flags]
* [authelia-gen](authelia-gen.md) - Authelia's generator tooling
* [authelia-gen code keys](authelia-gen_code_keys.md) - Generate the list of valid configuration keys
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-gen code keys"
description: "Reference for the authelia-gen code keys command."
lead: ""
date: 2022-06-03T10:57:43+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -32,4 +32,4 @@ authelia-gen code keys [flags]
* [authelia-gen code](authelia-gen_code.md) - Generate code
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-gen docs"
description: "Reference for the authelia-gen docs command."
lead: ""
date: 2022-06-03T10:57:43+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -33,4 +33,4 @@ authelia-gen docs [flags]
* [authelia-gen docs cli](authelia-gen_docs_cli.md) - Generate CLI docs
* [authelia-gen docs date](authelia-gen_docs_date.md) - Generate doc dates
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-gen docs cli"
description: "Reference for the authelia-gen docs cli command."
lead: ""
date: 2022-06-03T10:57:43+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -37,4 +37,4 @@ authelia-gen docs cli [flags]
* [authelia-gen docs](authelia-gen_docs.md) - Generate docs
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-gen docs time"
description: "Reference for the authelia-gen docs time command."
lead: ""
date: 2022-06-03T11:17:29+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:

View File

@ -2,7 +2,7 @@
title: "authelia-scripts"
description: ""
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:

View File

@ -2,7 +2,7 @@
title: "authelia-scripts"
description: "Reference for the authelia-scripts command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -49,4 +49,4 @@ authelia-scripts help
* [authelia-scripts unittest](authelia-scripts_unittest.md) - Run unit tests
* [authelia-scripts xflags](authelia-scripts_xflags.md) - Generate X LDFlags for building Authelia
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-scripts bootstrap"
description: "Reference for the authelia-scripts bootstrap command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -47,4 +47,4 @@ authelia-scripts bootstrap
* [authelia-scripts](authelia-scripts.md) - A utility used in the Authelia development process.
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-scripts build"
description: "Reference for the authelia-scripts build command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -47,4 +47,4 @@ authelia-scripts build
* [authelia-scripts](authelia-scripts.md) - A utility used in the Authelia development process.
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-scripts certificates"
description: "Reference for the authelia-scripts certificates command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
lastmod: 2022-06-03T11:17:29+10:00
draft: false
images: []

View File

@ -2,7 +2,7 @@
title: "authelia-scripts certificates generate"
description: "Reference for the authelia-scripts certificates generate command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
lastmod: 2022-06-03T11:17:29+10:00
draft: false
images: []

View File

@ -2,7 +2,7 @@
title: "authelia-scripts ci"
description: "Reference for the authelia-scripts ci command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -47,4 +47,4 @@ authelia-scripts ci
* [authelia-scripts](authelia-scripts.md) - A utility used in the Authelia development process.
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-scripts clean"
description: "Reference for the authelia-scripts clean command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -47,4 +47,4 @@ authelia-scripts clean
* [authelia-scripts](authelia-scripts.md) - A utility used in the Authelia development process.
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-scripts docker"
description: "Reference for the authelia-scripts docker command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -49,4 +49,4 @@ authelia-scripts docker
* [authelia-scripts docker build](authelia-scripts_docker_build.md) - Build the docker image of Authelia
* [authelia-scripts docker push-manifest](authelia-scripts_docker_push-manifest.md) - Push Authelia docker manifest to the Docker registries
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-scripts docker build"
description: "Reference for the authelia-scripts docker build command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -48,4 +48,4 @@ authelia-scripts docker build
* [authelia-scripts docker](authelia-scripts_docker.md) - Commands related to building and publishing docker image
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-scripts docker push-manifest"
description: "Reference for the authelia-scripts docker push-manifest command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -47,4 +47,4 @@ authelia-scripts docker push-manifest
* [authelia-scripts docker](authelia-scripts_docker.md) - Commands related to building and publishing docker image
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-scripts hash-password"
description: "Reference for the authelia-scripts hash-password command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
lastmod: 2022-06-03T11:17:29+10:00
draft: false
images: []

View File

@ -2,7 +2,7 @@
title: "authelia-scripts rsa"
description: "Reference for the authelia-scripts rsa command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
lastmod: 2022-06-03T11:17:29+10:00
draft: false
images: []

View File

@ -2,7 +2,7 @@
title: "authelia-scripts rsa generate"
description: "Reference for the authelia-scripts rsa generate command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
lastmod: 2022-06-03T11:17:29+10:00
draft: false
images: []

View File

@ -2,7 +2,7 @@
title: "authelia-scripts serve"
description: "Reference for the authelia-scripts serve command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -47,4 +47,4 @@ authelia-scripts serve test.yml
* [authelia-scripts](authelia-scripts.md) - A utility used in the Authelia development process.
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-scripts suites"
description: "Reference for the authelia-scripts suites command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -51,4 +51,4 @@ authelia-scripts suites
* [authelia-scripts suites teardown](authelia-scripts_suites_teardown.md) - Teardown a test suite environment
* [authelia-scripts suites test](authelia-scripts_suites_test.md) - Run a test suite
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-scripts suites list"
description: "Reference for the authelia-scripts suites list command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -49,4 +49,4 @@ authelia-scripts suites list
* [authelia-scripts suites](authelia-scripts_suites.md) - Commands related to suites management
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-scripts suites setup"
description: "Reference for the authelia-scripts suites setup command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -49,4 +49,4 @@ authelia-scripts suites setup Standalone
* [authelia-scripts suites](authelia-scripts_suites.md) - Commands related to suites management
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-scripts suites teardown"
description: "Reference for the authelia-scripts suites teardown command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -49,4 +49,4 @@ authelia-scripts suites setup Standalone
* [authelia-scripts suites](authelia-scripts_suites.md) - Commands related to suites management
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-scripts suites test"
description: "Reference for the authelia-scripts suites test command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -52,4 +52,4 @@ authelia-scripts suites test Standalone
* [authelia-scripts suites](authelia-scripts_suites.md) - Commands related to suites management
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-scripts unittest"
description: "Reference for the authelia-scripts unittest command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -47,4 +47,4 @@ authelia-scripts unittest
* [authelia-scripts](authelia-scripts.md) - A utility used in the Authelia development process.
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia-scripts xflags"
description: "Reference for the authelia-scripts xflags command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -49,4 +49,4 @@ authelia-scripts xflags
* [authelia-scripts](authelia-scripts.md) - A utility used in the Authelia development process.
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia"
description: ""
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:

View File

@ -2,7 +2,7 @@
title: "authelia"
description: "Reference for the authelia command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -24,7 +24,7 @@ An open-source authentication and authorization server providing
two-factor authentication and single sign-on (SSO) for your
applications via a web portal.
Documentation is available at: https://www.authelia.com/docs
Documentation is available at: https://www.authelia.com/
```
authelia [flags]
@ -49,10 +49,9 @@ authelia --config /etc/authelia/config/
* [authelia access-control](authelia_access-control.md) - Helpers for the access control system
* [authelia build-info](authelia_build-info.md) - Show the build information of Authelia
* [authelia certificates](authelia_certificates.md) - Commands related to certificate generation
* [authelia hash-password](authelia_hash-password.md) - Hash a password to be used in file-based users database.
* [authelia rsa](authelia_rsa.md) - Commands related to rsa keypair generation
* [authelia crypto](authelia_crypto.md) - Perform cryptographic operations
* [authelia hash-password](authelia_hash-password.md) - Hash a password to be used in file-based users database
* [authelia storage](authelia_storage.md) - Manage the Authelia storage
* [authelia validate-config](authelia_validate-config.md) - Check a configuration against the internal configuration validation mechanisms
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia access-control"
description: "Reference for the authelia access-control command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -37,4 +37,4 @@ authelia access-control --help
* [authelia](authelia.md) - authelia untagged-unknown-dirty (master, unknown)
* [authelia access-control check-policy](authelia_access-control_check-policy.md) - Checks a request against the access control rules to determine what policy would be applied
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia access-control check-policy"
description: "Reference for the authelia access-control check-policy command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -53,7 +53,7 @@ authelia access-control check-policy --config config.yml --url https://example.c
### Options
```
-c, --config strings configuration files to load (default [config.yml])
-c, --config strings configuration files to load (default [configuration.yml])
--groups strings the groups of the subject
-h, --help help for check-policy
--ip string the ip of the subject
@ -67,4 +67,4 @@ authelia access-control check-policy --config config.yml --url https://example.c
* [authelia access-control](authelia_access-control.md) - Helpers for the access control system
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia build-info"
description: "Reference for the authelia build-info command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -49,4 +49,4 @@ authelia build-info
* [authelia](authelia.md) - authelia untagged-unknown-dirty (master, unknown)
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -1,43 +0,0 @@
---
title: "authelia certificates"
description: "Reference for the authelia certificates command."
lead: ""
date: 2022-05-31T11:13:56+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia certificates
Commands related to certificate generation
### Synopsis
Commands related to certificate generation.
This subcommand allows preforming X509 certificate tasks.
### Examples
```
authelia certificates --help
```
### Options
```
-h, --help help for certificates
--host strings Comma-separated hostnames and IPs to generate a certificate for
```
### SEE ALSO
* [authelia](authelia.md) - authelia untagged-unknown-dirty (master, unknown)
* [authelia certificates generate](authelia_certificates_generate.md) - Generate a self-signed certificate
###### Auto generated by spf13/cobra on 13-Jun-2022

View File

@ -1,59 +0,0 @@
---
title: "authelia certificates generate"
description: "Reference for the authelia certificates generate command."
lead: ""
date: 2022-05-31T11:13:56+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia certificates generate
Generate a self-signed certificate
### Synopsis
Generate a self-signed certificate.
This subcommand allows generating self-signed certificates.
```
authelia certificates generate [flags]
```
### Examples
```
authelia certificates generate
authelia certificates generate --dir ./out
```
### Options
```
--ca Whether this cert should be its own Certificate Authority
--dir string Target directory where the certificate and keys will be stored
--duration duration Duration that certificate is valid for (default 8760h0m0s)
--ecdsa-curve string ECDSA curve to use to generate a key. Valid values are P224, P256 (recommended), P384, P521
--ed25519 Generate an Ed25519 key
-h, --help help for generate
--rsa-bits int Size of RSA key to generate. Ignored if --ecdsa-curve is set (default 2048)
--start-date string Creation date formatted as Jan 1 15:04:05 2011
```
### Options inherited from parent commands
```
--host strings Comma-separated hostnames and IPs to generate a certificate for
```
### SEE ALSO
* [authelia certificates](authelia_certificates.md) - Commands related to certificate generation
###### Auto generated by spf13/cobra on 13-Jun-2022

View File

@ -0,0 +1,43 @@
---
title: "authelia crypto"
description: "Reference for the authelia crypto command."
lead: ""
date: 2022-06-27T12:16:00+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia crypto
Perform cryptographic operations
### Synopsis
Perform cryptographic operations.
This subcommand allows preforming cryptographic certificate, key pair, etc tasks.
### Examples
```
authelia crypto --help
```
### Options
```
-h, --help help for crypto
```
### SEE ALSO
* [authelia](authelia.md) - authelia untagged-unknown-dirty (master, unknown)
* [authelia crypto certificate](authelia_crypto_certificate.md) - Perform certificate cryptographic operations
* [authelia crypto pair](authelia_crypto_pair.md) - Perform key pair cryptographic operations
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -0,0 +1,44 @@
---
title: "authelia crypto certificate"
description: "Reference for the authelia crypto certificate command."
lead: ""
date: 2022-06-27T12:16:00+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia crypto certificate
Perform certificate cryptographic operations
### Synopsis
Perform certificate cryptographic operations.
This subcommand allows preforming certificate cryptographic tasks.
### Examples
```
authelia crypto certificate --help
```
### Options
```
-h, --help help for certificate
```
### SEE ALSO
* [authelia crypto](authelia_crypto.md) - Perform cryptographic operations
* [authelia crypto certificate ecdsa](authelia_crypto_certificate_ecdsa.md) - Perform ECDSA certificate cryptographic operations
* [authelia crypto certificate ed25519](authelia_crypto_certificate_ed25519.md) - Perform Ed25519 certificate cryptographic operations
* [authelia crypto certificate rsa](authelia_crypto_certificate_rsa.md) - Perform RSA certificate cryptographic operations
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -0,0 +1,43 @@
---
title: "authelia crypto certificate ecdsa"
description: "Reference for the authelia crypto certificate ecdsa command."
lead: ""
date: 2022-06-27T12:16:00+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia crypto certificate ecdsa
Perform ECDSA certificate cryptographic operations
### Synopsis
Perform ECDSA certificate cryptographic operations.
This subcommand allows preforming ECDSA certificate cryptographic tasks.
### Examples
```
authelia crypto certificate ecdsa --help
```
### Options
```
-h, --help help for ecdsa
```
### SEE ALSO
* [authelia crypto certificate](authelia_crypto_certificate.md) - Perform certificate cryptographic operations
* [authelia crypto certificate ecdsa generate](authelia_crypto_certificate_ecdsa_generate.md) - Generate an ECDSA private key and certificate
* [authelia crypto certificate ecdsa request](authelia_crypto_certificate_ecdsa_request.md) - Generate an ECDSA private key and certificate signing request
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -0,0 +1,66 @@
---
title: "authelia crypto certificate ecdsa generate"
description: "Reference for the authelia crypto certificate ecdsa generate command."
lead: ""
date: 2022-06-27T12:16:00+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia crypto certificate ecdsa generate
Generate an ECDSA private key and certificate
### Synopsis
Generate an ECDSA private key and certificate.
This subcommand allows generating an ECDSA private key and certificate.
```
authelia crypto certificate ecdsa generate [flags]
```
### Examples
```
authelia crypto certificate ecdsa generate --help
```
### Options
```
--ca create the certificate as a certificate authority certificate
-c, --common-name string certificate common name
--country strings certificate country
-b, --curve string Sets the elliptic curve which can be P224, P256, P384, or P521 (default "P256")
-d, --directory string directory where the generated keys, certificates, etc will be stored
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
--extended-usage strings specify the extended usage types of the certificate
--file.ca-certificate string certificate authority certificate to use when signing this certificate (default "ca.public.crt")
--file.ca-private-key string certificate authority private key to use to signing this certificate (default "ca.private.pem")
--file.certificate string name of the file to export the certificate data to (default "public.crt")
--file.private-key string name of the file to export the private key data to (default "private.pem")
-h, --help help for generate
-l, --locality strings certificate locality
--not-before string earliest date and time the certificate is considered valid formatted as Jan 2 15:04:05 2006 (default is now)
-o, --organization strings certificate organization (default [Authelia])
--organizational-unit strings certificate organizational unit
--path.ca string source directory of the certificate authority files, if not provided the certificate will be self-signed
-p, --postcode strings certificate postcode
--province strings certificate province
--sans strings subject alternative names
--signature string signature algorithm for the certificate (default "SHA256")
-s, --street-address strings certificate street address
```
### SEE ALSO
* [authelia crypto certificate ecdsa](authelia_crypto_certificate_ecdsa.md) - Perform ECDSA certificate cryptographic operations
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -0,0 +1,61 @@
---
title: "authelia crypto certificate ecdsa request"
description: "Reference for the authelia crypto certificate ecdsa request command."
lead: ""
date: 2022-06-27T12:16:00+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia crypto certificate ecdsa request
Generate an ECDSA private key and certificate signing request
### Synopsis
Generate an ECDSA private key and certificate signing request.
This subcommand allows generating an ECDSA private key and certificate signing request.
```
authelia crypto certificate ecdsa request [flags]
```
### Examples
```
authelia crypto certificate ecdsa request --help
```
### Options
```
-c, --common-name string certificate common name
--country strings certificate country
-b, --curve string Sets the elliptic curve which can be P224, P256, P384, or P521 (default "P256")
-d, --directory string directory where the generated keys, certificates, etc will be stored
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
--file.csr string name of the file to export the certificate request data to (default "request.csr")
--file.private-key string name of the file to export the private key data to (default "private.pem")
-h, --help help for request
-l, --locality strings certificate locality
--not-before string earliest date and time the certificate is considered valid formatted as Jan 2 15:04:05 2006 (default is now)
-o, --organization strings certificate organization (default [Authelia])
--organizational-unit strings certificate organizational unit
-p, --postcode strings certificate postcode
--province strings certificate province
--sans strings subject alternative names
--signature string signature algorithm for the certificate (default "SHA256")
-s, --street-address strings certificate street address
```
### SEE ALSO
* [authelia crypto certificate ecdsa](authelia_crypto_certificate_ecdsa.md) - Perform ECDSA certificate cryptographic operations
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -0,0 +1,43 @@
---
title: "authelia crypto certificate ed25519"
description: "Reference for the authelia crypto certificate ed25519 command."
lead: ""
date: 2022-06-27T12:16:00+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia crypto certificate ed25519
Perform Ed25519 certificate cryptographic operations
### Synopsis
Perform Ed25519 certificate cryptographic operations.
This subcommand allows preforming Ed25519 certificate cryptographic tasks.
### Examples
```
authelia crypto certificate ed25519 --help
```
### Options
```
-h, --help help for ed25519
```
### SEE ALSO
* [authelia crypto certificate](authelia_crypto_certificate.md) - Perform certificate cryptographic operations
* [authelia crypto certificate ed25519 generate](authelia_crypto_certificate_ed25519_generate.md) - Generate an Ed25519 private key and certificate
* [authelia crypto certificate ed25519 request](authelia_crypto_certificate_ed25519_request.md) - Generate an Ed25519 private key and certificate signing request
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -0,0 +1,65 @@
---
title: "authelia crypto certificate ed25519 generate"
description: "Reference for the authelia crypto certificate ed25519 generate command."
lead: ""
date: 2022-06-27T12:16:00+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia crypto certificate ed25519 generate
Generate an Ed25519 private key and certificate
### Synopsis
Generate an Ed25519 private key and certificate.
This subcommand allows generating an Ed25519 private key and certificate.
```
authelia crypto certificate ed25519 generate [flags]
```
### Examples
```
authelia crypto certificate ed25519 request --help
```
### Options
```
--ca create the certificate as a certificate authority certificate
-c, --common-name string certificate common name
--country strings certificate country
-d, --directory string directory where the generated keys, certificates, etc will be stored
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
--extended-usage strings specify the extended usage types of the certificate
--file.ca-certificate string certificate authority certificate to use when signing this certificate (default "ca.public.crt")
--file.ca-private-key string certificate authority private key to use to signing this certificate (default "ca.private.pem")
--file.certificate string name of the file to export the certificate data to (default "public.crt")
--file.private-key string name of the file to export the private key data to (default "private.pem")
-h, --help help for generate
-l, --locality strings certificate locality
--not-before string earliest date and time the certificate is considered valid formatted as Jan 2 15:04:05 2006 (default is now)
-o, --organization strings certificate organization (default [Authelia])
--organizational-unit strings certificate organizational unit
--path.ca string source directory of the certificate authority files, if not provided the certificate will be self-signed
-p, --postcode strings certificate postcode
--province strings certificate province
--sans strings subject alternative names
--signature string signature algorithm for the certificate (default "SHA256")
-s, --street-address strings certificate street address
```
### SEE ALSO
* [authelia crypto certificate ed25519](authelia_crypto_certificate_ed25519.md) - Perform Ed25519 certificate cryptographic operations
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -0,0 +1,60 @@
---
title: "authelia crypto certificate ed25519 request"
description: "Reference for the authelia crypto certificate ed25519 request command."
lead: ""
date: 2022-06-27T12:16:00+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia crypto certificate ed25519 request
Generate an Ed25519 private key and certificate signing request
### Synopsis
Generate an Ed25519 private key and certificate signing request.
This subcommand allows generating an Ed25519 private key and certificate signing request.
```
authelia crypto certificate ed25519 request [flags]
```
### Examples
```
authelia crypto certificate ed25519 request --help
```
### Options
```
-c, --common-name string certificate common name
--country strings certificate country
-d, --directory string directory where the generated keys, certificates, etc will be stored
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
--file.csr string name of the file to export the certificate request data to (default "request.csr")
--file.private-key string name of the file to export the private key data to (default "private.pem")
-h, --help help for request
-l, --locality strings certificate locality
--not-before string earliest date and time the certificate is considered valid formatted as Jan 2 15:04:05 2006 (default is now)
-o, --organization strings certificate organization (default [Authelia])
--organizational-unit strings certificate organizational unit
-p, --postcode strings certificate postcode
--province strings certificate province
--sans strings subject alternative names
--signature string signature algorithm for the certificate (default "SHA256")
-s, --street-address strings certificate street address
```
### SEE ALSO
* [authelia crypto certificate ed25519](authelia_crypto_certificate_ed25519.md) - Perform Ed25519 certificate cryptographic operations
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -0,0 +1,43 @@
---
title: "authelia crypto certificate rsa"
description: "Reference for the authelia crypto certificate rsa command."
lead: ""
date: 2022-06-27T12:16:00+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia crypto certificate rsa
Perform RSA certificate cryptographic operations
### Synopsis
Perform RSA certificate cryptographic operations.
This subcommand allows preforming RSA certificate cryptographic tasks.
### Examples
```
authelia crypto certificate rsa --help
```
### Options
```
-h, --help help for rsa
```
### SEE ALSO
* [authelia crypto certificate](authelia_crypto_certificate.md) - Perform certificate cryptographic operations
* [authelia crypto certificate rsa generate](authelia_crypto_certificate_rsa_generate.md) - Generate an RSA private key and certificate
* [authelia crypto certificate rsa request](authelia_crypto_certificate_rsa_request.md) - Generate an RSA private key and certificate signing request
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -0,0 +1,66 @@
---
title: "authelia crypto certificate rsa generate"
description: "Reference for the authelia crypto certificate rsa generate command."
lead: ""
date: 2022-06-27T12:16:00+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia crypto certificate rsa generate
Generate an RSA private key and certificate
### Synopsis
Generate an RSA private key and certificate.
This subcommand allows generating an RSA private key and certificate.
```
authelia crypto certificate rsa generate [flags]
```
### Examples
```
authelia crypto certificate rsa generate --help
```
### Options
```
-b, --bits int number of RSA bits for the certificate (default 2048)
--ca create the certificate as a certificate authority certificate
-c, --common-name string certificate common name
--country strings certificate country
-d, --directory string directory where the generated keys, certificates, etc will be stored
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
--extended-usage strings specify the extended usage types of the certificate
--file.ca-certificate string certificate authority certificate to use when signing this certificate (default "ca.public.crt")
--file.ca-private-key string certificate authority private key to use to signing this certificate (default "ca.private.pem")
--file.certificate string name of the file to export the certificate data to (default "public.crt")
--file.private-key string name of the file to export the private key data to (default "private.pem")
-h, --help help for generate
-l, --locality strings certificate locality
--not-before string earliest date and time the certificate is considered valid formatted as Jan 2 15:04:05 2006 (default is now)
-o, --organization strings certificate organization (default [Authelia])
--organizational-unit strings certificate organizational unit
--path.ca string source directory of the certificate authority files, if not provided the certificate will be self-signed
-p, --postcode strings certificate postcode
--province strings certificate province
--sans strings subject alternative names
--signature string signature algorithm for the certificate (default "SHA256")
-s, --street-address strings certificate street address
```
### SEE ALSO
* [authelia crypto certificate rsa](authelia_crypto_certificate_rsa.md) - Perform RSA certificate cryptographic operations
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -0,0 +1,61 @@
---
title: "authelia crypto certificate rsa request"
description: "Reference for the authelia crypto certificate rsa request command."
lead: ""
date: 2022-06-27T12:16:00+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia crypto certificate rsa request
Generate an RSA private key and certificate signing request
### Synopsis
Generate an RSA private key and certificate signing request.
This subcommand allows generating an RSA private key and certificate signing request.
```
authelia crypto certificate rsa request [flags]
```
### Examples
```
authelia crypto certificate rsa request --help
```
### Options
```
-b, --bits int number of RSA bits for the certificate (default 2048)
-c, --common-name string certificate common name
--country strings certificate country
-d, --directory string directory where the generated keys, certificates, etc will be stored
--duration duration duration of time the certificate is valid for (default 8760h0m0s)
--file.csr string name of the file to export the certificate request data to (default "request.csr")
--file.private-key string name of the file to export the private key data to (default "private.pem")
-h, --help help for request
-l, --locality strings certificate locality
--not-before string earliest date and time the certificate is considered valid formatted as Jan 2 15:04:05 2006 (default is now)
-o, --organization strings certificate organization (default [Authelia])
--organizational-unit strings certificate organizational unit
-p, --postcode strings certificate postcode
--province strings certificate province
--sans strings subject alternative names
--signature string signature algorithm for the certificate (default "SHA256")
-s, --street-address strings certificate street address
```
### SEE ALSO
* [authelia crypto certificate rsa](authelia_crypto_certificate_rsa.md) - Perform RSA certificate cryptographic operations
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -0,0 +1,44 @@
---
title: "authelia crypto pair"
description: "Reference for the authelia crypto pair command."
lead: ""
date: 2022-06-27T12:16:00+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia crypto pair
Perform key pair cryptographic operations
### Synopsis
Perform key pair cryptographic operations.
This subcommand allows preforming key pair cryptographic tasks.
### Examples
```
authelia crypto pair --help
```
### Options
```
-h, --help help for pair
```
### SEE ALSO
* [authelia crypto](authelia_crypto.md) - Perform cryptographic operations
* [authelia crypto pair ecdsa](authelia_crypto_pair_ecdsa.md) - Perform ECDSA key pair cryptographic operations
* [authelia crypto pair ed25519](authelia_crypto_pair_ed25519.md) - Perform Ed25519 key pair cryptographic operations
* [authelia crypto pair rsa](authelia_crypto_pair_rsa.md) - Perform RSA key pair cryptographic operations
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -0,0 +1,46 @@
---
title: "authelia crypto pair ecdsa"
description: "Reference for the authelia crypto pair ecdsa command."
lead: ""
date: 2022-06-27T12:16:00+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia crypto pair ecdsa
Perform ECDSA key pair cryptographic operations
### Synopsis
Perform ECDSA key pair cryptographic operations.
This subcommand allows preforming ECDSA key pair cryptographic tasks.
```
authelia crypto pair ecdsa [flags]
```
### Examples
```
authelia crypto pair ecdsa --help
```
### Options
```
-h, --help help for ecdsa
```
### SEE ALSO
* [authelia crypto pair](authelia_crypto_pair.md) - Perform key pair cryptographic operations
* [authelia crypto pair ecdsa generate](authelia_crypto_pair_ecdsa_generate.md) - Generate a cryptographic ECDSA key pair
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -0,0 +1,50 @@
---
title: "authelia crypto pair ecdsa generate"
description: "Reference for the authelia crypto pair ecdsa generate command."
lead: ""
date: 2022-06-27T12:16:00+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia crypto pair ecdsa generate
Generate a cryptographic ECDSA key pair
### Synopsis
Generate a cryptographic ECDSA key pair.
This subcommand allows generating an ECDSA key pair.
```
authelia crypto pair ecdsa generate [flags]
```
### Examples
```
authelia crypto pair ecdsa generate --help
```
### Options
```
-b, --curve string Sets the elliptic curve which can be P224, P256, P384, or P521 (default "P256")
-d, --directory string directory where the generated keys, certificates, etc will be stored
--file.private-key string name of the file to export the private key data to (default "private.pem")
--file.public-key string name of the file to export the public key data to (default "public.pem")
-h, --help help for generate
--pkcs8 force PKCS #8 ASN.1 format
```
### SEE ALSO
* [authelia crypto pair ecdsa](authelia_crypto_pair_ecdsa.md) - Perform ECDSA key pair cryptographic operations
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -0,0 +1,46 @@
---
title: "authelia crypto pair ed25519"
description: "Reference for the authelia crypto pair ed25519 command."
lead: ""
date: 2022-06-27T12:16:00+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia crypto pair ed25519
Perform Ed25519 key pair cryptographic operations
### Synopsis
Perform Ed25519 key pair cryptographic operations.
This subcommand allows preforming Ed25519 key pair cryptographic tasks.
```
authelia crypto pair ed25519 [flags]
```
### Examples
```
authelia crypto pair ed25519 --help
```
### Options
```
-h, --help help for ed25519
```
### SEE ALSO
* [authelia crypto pair](authelia_crypto_pair.md) - Perform key pair cryptographic operations
* [authelia crypto pair ed25519 generate](authelia_crypto_pair_ed25519_generate.md) - Generate a cryptographic Ed25519 key pair
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -0,0 +1,49 @@
---
title: "authelia crypto pair ed25519 generate"
description: "Reference for the authelia crypto pair ed25519 generate command."
lead: ""
date: 2022-06-27T12:16:00+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia crypto pair ed25519 generate
Generate a cryptographic Ed25519 key pair
### Synopsis
Generate a cryptographic Ed25519 key pair.
This subcommand allows generating an Ed25519 key pair.
```
authelia crypto pair ed25519 generate [flags]
```
### Examples
```
authelia crypto pair ed25519 generate --help
```
### Options
```
-d, --directory string directory where the generated keys, certificates, etc will be stored
--file.private-key string name of the file to export the private key data to (default "private.pem")
--file.public-key string name of the file to export the public key data to (default "public.pem")
-h, --help help for generate
--pkcs8 force PKCS #8 ASN.1 format
```
### SEE ALSO
* [authelia crypto pair ed25519](authelia_crypto_pair_ed25519.md) - Perform Ed25519 key pair cryptographic operations
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -0,0 +1,46 @@
---
title: "authelia crypto pair rsa"
description: "Reference for the authelia crypto pair rsa command."
lead: ""
date: 2022-06-27T12:16:00+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia crypto pair rsa
Perform RSA key pair cryptographic operations
### Synopsis
Perform RSA key pair cryptographic operations.
This subcommand allows preforming RSA key pair cryptographic tasks.
```
authelia crypto pair rsa [flags]
```
### Examples
```
authelia crypto pair rsa --help
```
### Options
```
-h, --help help for rsa
```
### SEE ALSO
* [authelia crypto pair](authelia_crypto_pair.md) - Perform key pair cryptographic operations
* [authelia crypto pair rsa generate](authelia_crypto_pair_rsa_generate.md) - Generate a cryptographic RSA key pair
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -0,0 +1,50 @@
---
title: "authelia crypto pair rsa generate"
description: "Reference for the authelia crypto pair rsa generate command."
lead: ""
date: 2022-06-27T12:16:00+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia crypto pair rsa generate
Generate a cryptographic RSA key pair
### Synopsis
Generate a cryptographic RSA key pair.
This subcommand allows generating an RSA key pair.
```
authelia crypto pair rsa generate [flags]
```
### Examples
```
authelia crypto pair rsa generate --help
```
### Options
```
-b, --bits int number of RSA bits for the certificate (default 2048)
-d, --directory string directory where the generated keys, certificates, etc will be stored
--file.private-key string name of the file to export the private key data to (default "private.pem")
--file.public-key string name of the file to export the public key data to (default "public.pem")
-h, --help help for generate
--pkcs8 force PKCS #8 ASN.1 format
```
### SEE ALSO
* [authelia crypto pair rsa](authelia_crypto_pair_rsa.md) - Perform RSA key pair cryptographic operations
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia hash-password"
description: "Reference for the authelia hash-password command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -14,7 +14,7 @@ toc: true
## authelia hash-password
Hash a password to be used in file-based users database.
Hash a password to be used in file-based users database
### Synopsis
@ -53,4 +53,4 @@ authelia hash-password --key-length=64 -- 'mypass'
* [authelia](authelia.md) - authelia untagged-unknown-dirty (master, unknown)
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -1,42 +0,0 @@
---
title: "authelia rsa"
description: "Reference for the authelia rsa command."
lead: ""
date: 2022-05-31T11:13:56+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia rsa
Commands related to rsa keypair generation
### Synopsis
Commands related to rsa keypair generation.
This subcommand allows performing RSA keypair tasks.
### Examples
```
authelia rsa --help
```
### Options
```
-h, --help help for rsa
```
### SEE ALSO
* [authelia](authelia.md) - authelia untagged-unknown-dirty (master, unknown)
* [authelia rsa generate](authelia_rsa_generate.md) - Generate a RSA keypair
###### Auto generated by spf13/cobra on 13-Jun-2022

View File

@ -1,48 +0,0 @@
---
title: "authelia rsa generate"
description: "Reference for the authelia rsa generate command."
lead: ""
date: 2022-05-31T11:13:56+10:00
draft: false
images: []
menu:
reference:
parent: "cli-authelia"
weight: 330
toc: true
---
## authelia rsa generate
Generate a RSA keypair
### Synopsis
Generate a RSA keypair.
This subcommand allows generating an RSA keypair.
```
authelia rsa generate [flags]
```
### Examples
```
authelia rsa generate
authelia rsa generate --dir ./out
```
### Options
```
-d, --dir string Target directory where the keypair will be stored
-h, --help help for generate
-b, --key-size int Sets the key size in bits (default 2048)
```
### SEE ALSO
* [authelia rsa](authelia_rsa.md) - Commands related to rsa keypair generation
###### Auto generated by spf13/cobra on 13-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage"
description: "Reference for the authelia storage command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -62,4 +62,4 @@ authelia storage --help
* [authelia storage schema-info](authelia_storage_schema-info.md) - Show the storage information
* [authelia storage user](authelia_storage_user.md) - Manages user settings
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage encryption"
description: "Reference for the authelia storage encryption command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -63,4 +63,4 @@ authelia storage encryption --help
* [authelia storage encryption change-key](authelia_storage_encryption_change-key.md) - Changes the encryption key
* [authelia storage encryption check](authelia_storage_encryption_check.md) - Checks the encryption key against the database data
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage encryption change-key"
description: "Reference for the authelia storage encryption change-key command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -67,4 +67,4 @@ authelia storage encryption change-key --encryption-key b3453fde-ecc2-4a1f-9422-
* [authelia storage encryption](authelia_storage_encryption.md) - Manage storage encryption
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage encryption check"
description: "Reference for the authelia storage encryption check command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -69,4 +69,4 @@ authelia storage encryption check --verbose --encryption-key b3453fde-ecc2-4a1f-
* [authelia storage encryption](authelia_storage_encryption.md) - Manage storage encryption
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage migrate"
description: "Reference for the authelia storage migrate command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -66,4 +66,4 @@ authelia storage migrate --help
* [authelia storage migrate list-up](authelia_storage_migrate_list-up.md) - List the up migrations available
* [authelia storage migrate up](authelia_storage_migrate_up.md) - Perform a migration up
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage migrate down"
description: "Reference for the authelia storage migrate down command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -71,4 +71,4 @@ authelia storage migrate down --target 20 --encryption-key b3453fde-ecc2-4a1f-94
* [authelia storage migrate](authelia_storage_migrate.md) - Perform or list migrations
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage migrate history"
description: "Reference for the authelia storage migrate history command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -67,4 +67,4 @@ authelia storage migrate history --encryption-key b3453fde-ecc2-4a1f-9422-2707dd
* [authelia storage migrate](authelia_storage_migrate.md) - Perform or list migrations
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage migrate list-down"
description: "Reference for the authelia storage migrate list-down command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -68,4 +68,4 @@ authelia storage migrate list-down --encryption-key b3453fde-ecc2-4a1f-9422-2707
* [authelia storage migrate](authelia_storage_migrate.md) - Perform or list migrations
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage migrate list-up"
description: "Reference for the authelia storage migrate list-up command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -68,4 +68,4 @@ authelia storage migrate list-up --encryption-key b3453fde-ecc2-4a1f-9422-2707dd
* [authelia storage migrate](authelia_storage_migrate.md) - Perform or list migrations
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage migrate up"
description: "Reference for the authelia storage migrate up command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -70,4 +70,4 @@ authelia storage migrate up --encryption-key b3453fde-ecc2-4a1f-9422-2707ddbed49
* [authelia storage migrate](authelia_storage_migrate.md) - Perform or list migrations
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage schema-info"
description: "Reference for the authelia storage schema-info command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -67,4 +67,4 @@ authelia storage schema-info --encryption-key b3453fde-ecc2-4a1f-9422-2707ddbed4
* [authelia storage](authelia_storage.md) - Manage the Authelia storage
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage user"
description: "Reference for the authelia storage user command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -63,4 +63,4 @@ authelia storage user --help
* [authelia storage user identifiers](authelia_storage_user_identifiers.md) - Manage user opaque identifiers
* [authelia storage user totp](authelia_storage_user_totp.md) - Manage TOTP configurations
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage user identifiers"
description: "Reference for the authelia storage user identifiers command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -65,4 +65,4 @@ authelia storage user identifiers --help
* [authelia storage user identifiers generate](authelia_storage_user_identifiers_generate.md) - Generate opaque identifiers in bulk
* [authelia storage user identifiers import](authelia_storage_user_identifiers_import.md) - Import the identifiers from a YAML file
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage user identifiers add"
description: "Reference for the authelia storage user identifiers add command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -70,4 +70,4 @@ authelia storage user identifiers add john --identifier f0919359-9d15-4e15-bcba-
* [authelia storage user identifiers](authelia_storage_user_identifiers.md) - Manage user opaque identifiers
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage user identifiers export"
description: "Reference for the authelia storage user identifiers export command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -69,4 +69,4 @@ authelia storage user identifiers export --file export.yaml --encryption-key b34
* [authelia storage user identifiers](authelia_storage_user_identifiers.md) - Manage user opaque identifiers
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage user identifiers generate"
description: "Reference for the authelia storage user identifiers generate command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -72,4 +72,4 @@ authelia storage user identifiers generate --users john,mary --services openid -
* [authelia storage user identifiers](authelia_storage_user_identifiers.md) - Manage user opaque identifiers
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage user identifiers import"
description: "Reference for the authelia storage user identifiers import command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -72,4 +72,4 @@ authelia storage user identifiers import --file export.yaml --encryption-key b34
* [authelia storage user identifiers](authelia_storage_user_identifiers.md) - Manage user opaque identifiers
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage user totp"
description: "Reference for the authelia storage user totp command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -64,4 +64,4 @@ authelia storage user totp --help
* [authelia storage user totp export](authelia_storage_user_totp_export.md) - Perform exports of the TOTP configurations
* [authelia storage user totp generate](authelia_storage_user_totp_generate.md) - Generate a TOTP configuration for a user
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage user totp delete"
description: "Reference for the authelia storage user totp delete command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -67,4 +67,4 @@ authelia storage user totp delete john --encryption-key b3453fde-ecc2-4a1f-9422-
* [authelia storage user totp](authelia_storage_user_totp.md) - Manage TOTP configurations
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage user totp export"
description: "Reference for the authelia storage user totp export command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -70,4 +70,4 @@ authelia storage user totp export --format png --dir ./totp-qr --encryption-key
* [authelia storage user totp](authelia_storage_user_totp.md) - Manage TOTP configurations
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia storage user totp generate"
description: "Reference for the authelia storage user totp generate command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -79,4 +79,4 @@ authelia storage user totp generate john --algorithm SHA512 --config config.yml
* [authelia storage user totp](authelia_storage_user_totp.md) - Manage TOTP configurations
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -2,7 +2,7 @@
title: "authelia validate-config"
description: "Reference for the authelia validate-config command."
lead: ""
date: 2022-05-31T11:13:56+10:00
date: 2022-06-15T17:51:47+10:00
draft: false
images: []
menu:
@ -45,4 +45,4 @@ authelia validate-config --config config.yml
* [authelia](authelia.md) - authelia untagged-unknown-dirty (master, unknown)
###### Auto generated by spf13/cobra on 13-Jun-2022
###### Auto generated by spf13/cobra on 27-Jun-2022

View File

@ -60,7 +60,7 @@ if [[ $MODIFIED == "false" ]]; then
fi
echo "Generating SSL certificate for *.$DOMAIN"
sudo docker run -a stdout -v $PWD/traefik/certs:/tmp/certs authelia/authelia authelia certificates generate --host *.$DOMAIN --dir /tmp/certs/ > /dev/null
sudo docker run -a stdout -v $PWD/traefik/certs:/tmp/certs authelia/authelia authelia crypto certificate rsa generate --common-name="*.${DOMAIN}" --directory=/tmp/certs/ > /dev/null
if [[ $DOMAIN != "example.com" ]]; then
if [[ $(uname) == "Darwin" ]]; then

View File

@ -1,169 +0,0 @@
package commands
import (
"crypto/elliptic"
"fmt"
"log"
"os"
"path/filepath"
"time"
"github.com/spf13/cobra"
"github.com/authelia/authelia/v4/internal/utils"
)
func newCertificatesCmd() (cmd *cobra.Command) {
cmd = &cobra.Command{
Use: "certificates",
Short: cmdAutheliaCertificatesShort,
Long: cmdAutheliaCertificatesLong,
Example: cmdAutheliaCertificatesExample,
Args: cobra.NoArgs,
}
cmd.PersistentFlags().StringSlice("host", []string{}, "Comma-separated hostnames and IPs to generate a certificate for")
err := cmd.MarkPersistentFlagRequired("host")
if err != nil {
log.Fatal(err)
}
cmd.AddCommand(newCertificatesGenerateCmd())
return cmd
}
func newCertificatesGenerateCmd() (cmd *cobra.Command) {
cmd = &cobra.Command{
Use: "generate",
Short: cmdAutheliaCertificatesGenerateShort,
Long: cmdAutheliaCertificatesGenerateLong,
Example: cmdAutheliaCertificatesGenerateExample,
Args: cobra.NoArgs,
Run: cmdCertificatesGenerateRun,
}
cmd.Flags().String("start-date", "", "Creation date formatted as Jan 1 15:04:05 2011")
cmd.Flags().Duration("duration", 365*24*time.Hour, "Duration that certificate is valid for")
cmd.Flags().Bool("ca", false, "Whether this cert should be its own Certificate Authority")
cmd.Flags().Int("rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set")
cmd.Flags().String("ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256 (recommended), P384, P521")
cmd.Flags().Bool("ed25519", false, "Generate an Ed25519 key")
cmd.Flags().String("dir", "", "Target directory where the certificate and keys will be stored")
return cmd
}
func cmdCertificatesGenerateRun(cmd *cobra.Command, _ []string) {
// implementation retrieved from https://golang.org/src/crypto/tls/generate_cert.go
ecdsaCurve, err := cmd.Flags().GetString("ecdsa-curve")
if err != nil {
fmt.Printf("Failed to parse ecdsa-curve flag: %v\n", err)
os.Exit(1)
}
ed25519Key, err := cmd.Flags().GetBool("ed25519")
if err != nil {
fmt.Printf("Failed to parse ed25519 flag: %v\n", err)
os.Exit(1)
}
rsaBits, err := cmd.Flags().GetInt("rsa-bits")
if err != nil {
fmt.Printf("Failed to parse rsa-bits flag: %v\n", err)
os.Exit(1)
}
hosts, err := cmd.Flags().GetStringSlice("host")
if err != nil {
fmt.Printf("Failed to parse host flag: %v\n", err)
os.Exit(1)
}
validFrom, err := cmd.Flags().GetString("start-date")
if err != nil {
fmt.Printf("Failed to parse start-date flag: %v\n", err)
os.Exit(1)
}
validFor, err := cmd.Flags().GetDuration("duration")
if err != nil {
fmt.Printf("Failed to parse duration flag: %v\n", err)
os.Exit(1)
}
isCA, err := cmd.Flags().GetBool("ca")
if err != nil {
fmt.Printf("Failed to parse ca flag: %v\n", err)
os.Exit(1)
}
certificateTargetDirectory, err := cmd.Flags().GetString("dir")
if err != nil {
fmt.Printf("Failed to parse dir flag: %v\n", err)
os.Exit(1)
}
cmdCertificatesGenerateRunExtended(hosts, ecdsaCurve, validFrom, certificateTargetDirectory, ed25519Key, isCA, rsaBits, validFor)
}
func cmdCertificatesGenerateRunExtended(hosts []string, ecdsaCurve, validFrom, certificateTargetDirectory string, ed25519Key, isCA bool, rsaBits int, validFor time.Duration) {
certPath := filepath.Join(certificateTargetDirectory, "cert.pem")
keyPath := filepath.Join(certificateTargetDirectory, "key.pem")
var (
notBefore time.Time
err error
)
switch len(validFrom) {
case 0:
notBefore = time.Now()
default:
notBefore, err = time.Parse("Jan 2 15:04:05 2006", validFrom)
if err != nil {
log.Fatalf("Failed to parse start date: %v", err)
}
}
var privateKeyBuilder utils.PrivateKeyBuilder
switch ecdsaCurve {
case "":
if ed25519Key {
privateKeyBuilder = utils.Ed25519KeyBuilder{}
} else {
privateKeyBuilder = utils.RSAKeyBuilder{}.WithKeySize(rsaBits)
}
case "P224":
privateKeyBuilder = utils.ECDSAKeyBuilder{}.WithCurve(elliptic.P224())
case "P256":
privateKeyBuilder = utils.ECDSAKeyBuilder{}.WithCurve(elliptic.P256())
case "P384":
privateKeyBuilder = utils.ECDSAKeyBuilder{}.WithCurve(elliptic.P384())
case "P521":
privateKeyBuilder = utils.ECDSAKeyBuilder{}.WithCurve(elliptic.P521())
default:
log.Fatalf("Failed to generate private key: unrecognized elliptic curve: \"%s\"", ecdsaCurve)
}
certBytes, keyBytes, err := utils.GenerateCertificate(privateKeyBuilder, hosts, notBefore, validFor, isCA)
if err != nil {
log.Fatal(err)
}
err = os.WriteFile(certPath, certBytes, 0600)
if err != nil {
log.Fatalf("failed to write %s for writing: %v", certPath, err)
}
fmt.Printf("Certificate written to %s\n", certPath)
err = os.WriteFile(keyPath, keyBytes, 0600)
if err != nil {
log.Fatalf("failed to write %s for writing: %v", certPath, err)
}
fmt.Printf("Private Key written to %s\n", keyPath)
}

View File

@ -302,41 +302,85 @@ prior to deploying it.`
cmdAutheliaValidateConfigExample = `authelia validate-config
authelia validate-config --config config.yml`
cmdAutheliaCertificatesShort = "Commands related to certificate generation"
cmdAutheliaCryptoShort = "Perform cryptographic operations"
cmdAutheliaCertificatesLong = `Commands related to certificate generation.
cmdAutheliaCryptoLong = `Perform cryptographic operations.
This subcommand allows preforming X509 certificate tasks.`
This subcommand allows preforming cryptographic certificate, key pair, etc tasks.`
cmdAutheliaCertificatesExample = `authelia certificates --help`
cmdAutheliaCryptoExample = `authelia crypto --help`
cmdAutheliaCertificatesGenerateShort = "Generate a self-signed certificate"
cmdAutheliaCryptoCertificateShort = "Perform certificate cryptographic operations"
cmdAutheliaCertificatesGenerateLong = `Generate a self-signed certificate.
cmdAutheliaCryptoCertificateLong = `Perform certificate cryptographic operations.
This subcommand allows generating self-signed certificates.`
This subcommand allows preforming certificate cryptographic tasks.`
cmdAutheliaCertificatesGenerateExample = `authelia certificates generate
authelia certificates generate --dir ./out`
cmdAutheliaCryptoCertificateExample = `authelia crypto certificate --help`
cmdAutheliaRSAShort = "Commands related to rsa keypair generation"
fmtCmdAutheliaCryptoCertificateSubShort = "Perform %s certificate cryptographic operations"
cmdAutheliaRSALong = `Commands related to rsa keypair generation.
fmtCmdAutheliaCryptoCertificateSubLong = `Perform %s certificate cryptographic operations.
This subcommand allows performing RSA keypair tasks.`
This subcommand allows preforming %s certificate cryptographic tasks.`
cmdAutheliaRSAExample = `authelia rsa --help`
cmdAutheliaCryptoCertificateRSAExample = `authelia crypto certificate rsa --help`
cmdAutheliaRSAGenerateShort = "Generate a RSA keypair"
cmdAutheliaCryptoCertificateECDSAExample = `authelia crypto certificate ecdsa --help`
cmdAutheliaRSAGenerateLong = `Generate a RSA keypair.
cmdAutheliaCryptoCertificateEd25519Example = `authelia crypto certificate ed25519 --help`
This subcommand allows generating an RSA keypair.`
fmtCmdAutheliaCryptoCertificateGenerateRequestShort = "Generate an %s private key and %s"
cmdAutheliaRSAGenerateExample = `authelia rsa generate
authelia rsa generate --dir ./out`
fmtCmdAutheliaCryptoCertificateGenerateRequestLong = `Generate an %s private key and %s.
cmdAutheliaHashPasswordShort = "Hash a password to be used in file-based users database."
This subcommand allows generating an %s private key and %s.`
cmdAutheliaCryptoCertificateRSAGenerateExample = `authelia crypto certificate rsa generate --help`
cmdAutheliaCryptoCertificateECDSAGenerateExample = `authelia crypto certificate ecdsa generate --help`
cmdAutheliaCryptoCertificateEd25519GenerateExample = `authelia crypto certificate ed25519 request --help`
cmdAutheliaCryptoCertificateRSARequestExample = `authelia crypto certificate rsa request --help`
cmdAutheliaCryptoCertificateECDSARequestExample = `authelia crypto certificate ecdsa request --help`
cmdAutheliaCryptoCertificateEd25519RequestExample = `authelia crypto certificate ed25519 request --help`
cmdAutheliaCryptoPairShort = "Perform key pair cryptographic operations"
cmdAutheliaCryptoPairLong = `Perform key pair cryptographic operations.
This subcommand allows preforming key pair cryptographic tasks.`
cmdAutheliaCryptoPairExample = `authelia crypto pair --help`
cmdAutheliaCryptoPairSubShort = "Perform %s key pair cryptographic operations"
cmdAutheliaCryptoPairSubLong = `Perform %s key pair cryptographic operations.
This subcommand allows preforming %s key pair cryptographic tasks.`
cmdAutheliaCryptoPairRSAExample = `authelia crypto pair rsa --help`
cmdAutheliaCryptoPairECDSAExample = `authelia crypto pair ecdsa --help`
cmdAutheliaCryptoPairEd25519Example = `authelia crypto pair ed25519 --help`
fmtCmdAutheliaCryptoPairGenerateShort = "Generate a cryptographic %s key pair"
fmtCmdAutheliaCryptoPairGenerateLong = `Generate a cryptographic %s key pair.
This subcommand allows generating an %s key pair.`
cmdAutheliaCryptoPairRSAGenerateExample = `authelia crypto pair rsa generate --help`
cmdAutheliaCryptoPairECDSAGenerateExample = `authelia crypto pair ecdsa generate --help`
cmdAutheliaCryptoPairEd25519GenerateExample = `authelia crypto pair ed25519 generate --help`
cmdAutheliaHashPasswordShort = "Hash a password to be used in file-based users database"
cmdAutheliaHashPasswordLong = `Hash a password to be used in file-based users database.`
@ -364,6 +408,59 @@ var (
validStorageTOTPExportFormats = []string{storageTOTPExportFormatCSV, storageTOTPExportFormatURI, storageTOTPExportFormatPNG}
)
const (
timeLayoutCertificateNotBefore = "Jan 2 15:04:05 2006"
)
const (
cmdFlagNameDirectory = "directory"
cmdFlagNamePathCA = "path.ca"
cmdFlagNameFilePrivateKey = "file.private-key"
cmdFlagNameFilePublicKey = "file.public-key"
cmdFlagNameFileCertificate = "file.certificate"
cmdFlagNameFileCAPrivateKey = "file.ca-private-key"
cmdFlagNameFileCACertificate = "file.ca-certificate"
cmdFlagNameFileCSR = "file.csr"
cmdFlagNameExtendedUsage = "extended-usage"
cmdFlagNameSignature = "signature"
cmdFlagNameCA = "ca"
cmdFlagNameSANs = "sans"
cmdFlagNameCommonName = "common-name"
cmdFlagNameOrganization = "organization"
cmdFlagNameOrganizationalUnit = "organizational-unit"
cmdFlagNameCountry = "country"
cmdFlagNameProvince = "province"
cmdFlagNameLocality = "locality"
cmdFlagNameStreetAddress = "street-address"
cmdFlagNamePostcode = "postcode"
cmdFlagNameNotBefore = "not-before"
cmdFlagNameDuration = "duration"
cmdFlagNamePKCS8 = "pkcs8"
cmdFlagNameBits = "bits"
cmdFlagNameCurve = "curve"
)
const (
cmdUseCertificate = "certificate"
cmdUseGenerate = "generate"
cmdUseRequest = "request"
cmdUsePair = "pair"
cmdUseRSA = "rsa"
cmdUseECDSA = "ecdsa"
cmdUseEd25519 = "ed25519"
)
const (
cryptoCertPubCertOut = "certificate"
cryptoCertCSROut = "certificate signing request"
)
var (
errNoStorageProvider = errors.New("no storage provider configured")
)

View File

@ -0,0 +1,451 @@
package commands
import (
"crypto/ecdsa"
"crypto/ed25519"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"fmt"
"strings"
"time"
"github.com/spf13/cobra"
"github.com/authelia/authelia/v4/internal/utils"
)
func newCryptoCmd() (cmd *cobra.Command) {
cmd = &cobra.Command{
Use: "crypto",
Short: cmdAutheliaCryptoShort,
Long: cmdAutheliaCryptoLong,
Example: cmdAutheliaCryptoExample,
Args: cobra.NoArgs,
}
cmd.AddCommand(
newCryptoCertificateCmd(),
newCryptoPairCmd(),
)
return cmd
}
func newCryptoCertificateCmd() (cmd *cobra.Command) {
cmd = &cobra.Command{
Use: cmdUseCertificate,
Short: cmdAutheliaCryptoCertificateShort,
Long: cmdAutheliaCryptoCertificateLong,
Example: cmdAutheliaCryptoCertificateExample,
Args: cobra.NoArgs,
}
cmd.AddCommand(
newCryptoCertificateSubCmd(cmdUseRSA),
newCryptoCertificateSubCmd(cmdUseECDSA),
newCryptoCertificateSubCmd(cmdUseEd25519),
)
return cmd
}
func newCryptoCertificateSubCmd(use string) (cmd *cobra.Command) {
var (
example, useFmt string
)
useFmt = fmtCryptoUse(use)
switch use {
case cmdUseRSA:
example = cmdAutheliaCryptoCertificateRSAExample
case cmdUseECDSA:
example = cmdAutheliaCryptoCertificateECDSAExample
case cmdUseEd25519:
example = cmdAutheliaCryptoCertificateEd25519Example
}
cmd = &cobra.Command{
Use: use,
Short: fmt.Sprintf(fmtCmdAutheliaCryptoCertificateSubShort, useFmt),
Long: fmt.Sprintf(fmtCmdAutheliaCryptoCertificateSubLong, useFmt, useFmt),
Example: example,
Args: cobra.NoArgs,
}
cmd.AddCommand(newCryptoGenerateCmd(cmdUseCertificate, use), newCryptoCertificateRequestCmd(use))
return cmd
}
func newCryptoCertificateRequestCmd(algorithm string) (cmd *cobra.Command) {
cmd = &cobra.Command{
Use: cmdUseRequest,
Args: cobra.NoArgs,
RunE: cryptoCertificateRequestRunE,
}
cmdFlagsCryptoPrivateKey(cmd)
cmdFlagsCryptoCertificateCommon(cmd)
cmdFlagsCryptoCertificateRequest(cmd)
algorithmFmt := fmtCryptoUse(algorithm)
cmd.Short = fmt.Sprintf(fmtCmdAutheliaCryptoCertificateGenerateRequestShort, algorithmFmt, cryptoCertCSROut)
cmd.Long = fmt.Sprintf(fmtCmdAutheliaCryptoCertificateGenerateRequestLong, algorithmFmt, cryptoCertCSROut, algorithmFmt, cryptoCertCSROut)
switch algorithm {
case cmdUseRSA:
cmd.Example = cmdAutheliaCryptoCertificateRSARequestExample
cmdFlagsCryptoPrivateKeyRSA(cmd)
case cmdUseECDSA:
cmd.Example = cmdAutheliaCryptoCertificateECDSARequestExample
cmdFlagsCryptoPrivateKeyECDSA(cmd)
case cmdUseEd25519:
cmd.Example = cmdAutheliaCryptoCertificateEd25519RequestExample
cmdFlagsCryptoPrivateKeyEd25519(cmd)
}
return cmd
}
func newCryptoPairCmd() (cmd *cobra.Command) {
cmd = &cobra.Command{
Use: cmdUsePair,
Short: cmdAutheliaCryptoPairShort,
Long: cmdAutheliaCryptoPairLong,
Example: cmdAutheliaCryptoPairExample,
Args: cobra.NoArgs,
}
cmd.AddCommand(
newCryptoPairSubCmd(cmdUseRSA),
newCryptoPairSubCmd(cmdUseECDSA),
newCryptoPairSubCmd(cmdUseEd25519),
)
return cmd
}
func newCryptoPairSubCmd(use string) (cmd *cobra.Command) {
var (
example, useFmt string
)
useFmt = fmtCryptoUse(use)
switch use {
case cmdUseRSA:
example = cmdAutheliaCryptoPairRSAExample
case cmdUseECDSA:
example = cmdAutheliaCryptoPairECDSAExample
case cmdUseEd25519:
example = cmdAutheliaCryptoPairEd25519Example
}
cmd = &cobra.Command{
Use: use,
Short: fmt.Sprintf(cmdAutheliaCryptoPairSubShort, useFmt),
Long: fmt.Sprintf(cmdAutheliaCryptoPairSubLong, useFmt, useFmt),
Example: example,
Args: cobra.NoArgs,
RunE: cryptoGenerateRunE,
}
cmd.AddCommand(newCryptoGenerateCmd(cmdUsePair, use))
return cmd
}
func newCryptoGenerateCmd(category, algorithm string) (cmd *cobra.Command) {
cmd = &cobra.Command{
Use: cmdUseGenerate,
Args: cobra.NoArgs,
RunE: cryptoGenerateRunE,
}
cmdFlagsCryptoPrivateKey(cmd)
algorithmFmt := fmtCryptoUse(algorithm)
switch category {
case cmdUseCertificate:
cmdFlagsCryptoCertificateCommon(cmd)
cmdFlagsCryptoCertificateGenerate(cmd)
cmd.Short = fmt.Sprintf(fmtCmdAutheliaCryptoCertificateGenerateRequestShort, algorithmFmt, cryptoCertPubCertOut)
cmd.Long = fmt.Sprintf(fmtCmdAutheliaCryptoCertificateGenerateRequestLong, algorithmFmt, cryptoCertPubCertOut, algorithmFmt, cryptoCertPubCertOut)
switch algorithm {
case cmdUseRSA:
cmd.Example = cmdAutheliaCryptoCertificateRSAGenerateExample
cmdFlagsCryptoPrivateKeyRSA(cmd)
case cmdUseECDSA:
cmd.Example = cmdAutheliaCryptoCertificateECDSAGenerateExample
cmdFlagsCryptoPrivateKeyECDSA(cmd)
case cmdUseEd25519:
cmd.Example = cmdAutheliaCryptoCertificateEd25519GenerateExample
cmdFlagsCryptoPrivateKeyEd25519(cmd)
}
case cmdUsePair:
cmdFlagsCryptoPairGenerate(cmd)
cmd.Short = fmt.Sprintf(fmtCmdAutheliaCryptoPairGenerateShort, algorithmFmt)
cmd.Long = fmt.Sprintf(fmtCmdAutheliaCryptoPairGenerateLong, algorithmFmt, algorithmFmt)
switch algorithm {
case cmdUseRSA:
cmd.Example = cmdAutheliaCryptoPairRSAGenerateExample
cmdFlagsCryptoPrivateKeyRSA(cmd)
case cmdUseECDSA:
cmd.Example = cmdAutheliaCryptoPairECDSAGenerateExample
cmdFlagsCryptoPrivateKeyECDSA(cmd)
case cmdUseEd25519:
cmd.Example = cmdAutheliaCryptoPairEd25519GenerateExample
cmdFlagsCryptoPrivateKeyEd25519(cmd)
}
}
return cmd
}
func cryptoGenerateRunE(cmd *cobra.Command, args []string) (err error) {
var (
privateKey interface{}
)
if privateKey, err = cryptoGenPrivateKeyFromCmd(cmd); err != nil {
return err
}
if cmd.Parent().Parent().Use == cmdUseCertificate {
return cryptoCertificateGenerateRunE(cmd, args, privateKey)
}
return cryptoPairGenerateRunE(cmd, args, privateKey)
}
func cryptoCertificateRequestRunE(cmd *cobra.Command, _ []string) (err error) {
var (
privateKey interface{}
)
if privateKey, err = cryptoGenPrivateKeyFromCmd(cmd); err != nil {
return err
}
var (
template *x509.CertificateRequest
csr []byte
privateKeyPath, csrPath string
)
if template, err = cryptoGetCSRFromCmd(cmd); err != nil {
return err
}
b := strings.Builder{}
b.WriteString("Generating Certificate Request\n\n")
b.WriteString("Subject:\n")
b.WriteString(fmt.Sprintf("\tCommon Name: %s, Organization: %s, Organizational Unit: %s\n", template.Subject.CommonName, template.Subject.Organization, template.Subject.OrganizationalUnit))
b.WriteString(fmt.Sprintf("\tCountry: %v, Province: %v, Street Address: %v, Postal Code: %v, Locality: %v\n\n", template.Subject.Country, template.Subject.Province, template.Subject.StreetAddress, template.Subject.PostalCode, template.Subject.Locality))
b.WriteString("Properties:\n")
b.WriteString(fmt.Sprintf("\tSignature Algorithm: %s, Public Key Algorithm: %s", template.SignatureAlgorithm, template.PublicKeyAlgorithm))
switch k := privateKey.(type) {
case *rsa.PrivateKey:
b.WriteString(fmt.Sprintf(", Bits: %d", k.N.BitLen()))
case *ecdsa.PrivateKey:
b.WriteString(fmt.Sprintf(", Elliptic Curve: %s", k.Curve.Params().Name))
}
b.WriteString(fmt.Sprintf("\n\tSubject Alternative Names: %s\n\n", strings.Join(cryptoSANsToString(template.DNSNames, template.IPAddresses), ", ")))
if privateKeyPath, csrPath, err = cryptoGetWritePathsFromCmd(cmd); err != nil {
return err
}
b.WriteString("Output Paths:\n")
b.WriteString(fmt.Sprintf("\tPrivate Key: %s\n", privateKeyPath))
b.WriteString(fmt.Sprintf("\tCertificate Request: %s\n\n", csrPath))
fmt.Print(b.String())
b.Reset()
if csr, err = x509.CreateCertificateRequest(rand.Reader, template, privateKey); err != nil {
return fmt.Errorf("failed to create certificate request: %w", err)
}
if privateKeyPath, csrPath, err = cryptoGetWritePathsFromCmd(cmd); err != nil {
return err
}
if err = utils.WriteKeyToPEM(privateKey, privateKeyPath, false); err != nil {
return err
}
if err = utils.WriteCertificateBytesToPEM(csr, csrPath, true); err != nil {
return err
}
return nil
}
func cryptoCertificateGenerateRunE(cmd *cobra.Command, _ []string, privateKey interface{}) (err error) {
var (
template, caCertificate, parent *x509.Certificate
publicKey, caPrivateKey, signatureKey interface{}
)
if publicKey = utils.PublicKeyFromPrivateKey(privateKey); publicKey == nil {
return fmt.Errorf("failed to obtain public key from private key")
}
if caPrivateKey, caCertificate, err = cryptoGetCAFromCmd(cmd); err != nil {
return err
}
signatureKey = privateKey
if caPrivateKey != nil {
signatureKey = caPrivateKey
}
if template, err = cryptoGetCertificateFromCmd(cmd); err != nil {
return err
}
b := strings.Builder{}
b.WriteString("Generating Certificate\n\n")
b.WriteString(fmt.Sprintf("\tSerial: %x\n\n", template.SerialNumber))
switch caCertificate {
case nil:
parent = template
b.WriteString("Signed By:\n\tSelf-Signed\n")
default:
parent = caCertificate
b.WriteString(fmt.Sprintf("Signed By:\n\t%s\n", caCertificate.Subject.CommonName))
b.WriteString(fmt.Sprintf("\tSerial: %x, Expires: %s\n", caCertificate.SerialNumber, caCertificate.NotAfter.Format(time.RFC3339)))
}
b.WriteString("\nSubject:\n")
b.WriteString(fmt.Sprintf("\tCommon Name: %s, Organization: %s, Organizational Unit: %s\n", template.Subject.CommonName, template.Subject.Organization, template.Subject.OrganizationalUnit))
b.WriteString(fmt.Sprintf("\tCountry: %v, Province: %v, Street Address: %v, Postal Code: %v, Locality: %v\n\n", template.Subject.Country, template.Subject.Province, template.Subject.StreetAddress, template.Subject.PostalCode, template.Subject.Locality))
b.WriteString("Properties:\n")
b.WriteString(fmt.Sprintf("\tNot Before: %s, Not After: %s\n", template.NotBefore.Format(time.RFC3339), template.NotAfter.Format(time.RFC3339)))
b.WriteString(fmt.Sprintf("\tCA: %v, CSR: %v, Signature Algorithm: %s, Public Key Algorithm: %s", template.IsCA, false, template.SignatureAlgorithm, template.PublicKeyAlgorithm))
switch k := privateKey.(type) {
case *rsa.PrivateKey:
b.WriteString(fmt.Sprintf(", Bits: %d", k.N.BitLen()))
case *ecdsa.PrivateKey:
b.WriteString(fmt.Sprintf(", Elliptic Curve: %s", k.Curve.Params().Name))
}
b.WriteString(fmt.Sprintf("\n\tSubject Alternative Names: %s\n\n", strings.Join(cryptoSANsToString(template.DNSNames, template.IPAddresses), ", ")))
var (
privateKeyPath, certificatePath string
certificate []byte
)
if privateKeyPath, certificatePath, err = cryptoGetWritePathsFromCmd(cmd); err != nil {
return err
}
b.WriteString("Output Paths:\n")
b.WriteString(fmt.Sprintf("\tPrivate Key: %s\n", privateKeyPath))
b.WriteString(fmt.Sprintf("\tCertificate: %s\n\n", certificatePath))
fmt.Print(b.String())
b.Reset()
if certificate, err = x509.CreateCertificate(rand.Reader, template, parent, publicKey, signatureKey); err != nil {
return fmt.Errorf("failed to create certificate: %w", err)
}
if err = utils.WriteKeyToPEM(privateKey, privateKeyPath, false); err != nil {
return err
}
if err = utils.WriteCertificateBytesToPEM(certificate, certificatePath, false); err != nil {
return err
}
return nil
}
func cryptoPairGenerateRunE(cmd *cobra.Command, _ []string, privateKey interface{}) (err error) {
var (
privateKeyPath, publicKeyPath string
pkcs8 bool
)
if pkcs8, err = cmd.Flags().GetBool(cmdFlagNamePKCS8); err != nil {
return err
}
if privateKeyPath, publicKeyPath, err = cryptoGetWritePathsFromCmd(cmd); err != nil {
return err
}
b := strings.Builder{}
b.WriteString("Generating key pair\n\n")
switch k := privateKey.(type) {
case *rsa.PrivateKey:
b.WriteString(fmt.Sprintf("\tAlgorithm: RSA-%d %d bits\n\n", k.Size(), k.N.BitLen()))
case *ecdsa.PrivateKey:
b.WriteString(fmt.Sprintf("\tAlgorithm: ECDSA Curve %s\n\n", k.Curve.Params().Name))
case ed25519.PrivateKey:
b.WriteString("\tAlgorithm: Ed25519\n\n")
}
b.WriteString("Output Paths:\n")
b.WriteString(fmt.Sprintf("\tPrivate Key: %s\n", privateKeyPath))
b.WriteString(fmt.Sprintf("\tPublic Key: %s\n\n", publicKeyPath))
fmt.Print(b.String())
b.Reset()
if err = utils.WriteKeyToPEM(privateKey, privateKeyPath, pkcs8); err != nil {
return err
}
var publicKey interface{}
if publicKey = utils.PublicKeyFromPrivateKey(privateKey); publicKey == nil {
return fmt.Errorf("failed to obtain public key from private key")
}
if err = utils.WriteKeyToPEM(publicKey, publicKeyPath, pkcs8); err != nil {
return err
}
return nil
}

View File

@ -0,0 +1,426 @@
package commands
import (
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"crypto/x509/pkix"
"fmt"
"math/big"
"net"
"os"
"path/filepath"
"strings"
"time"
"github.com/spf13/cobra"
"github.com/authelia/authelia/v4/internal/utils"
)
func cmdFlagsCryptoCertificateCommon(cmd *cobra.Command) {
cmd.Flags().String(cmdFlagNameSignature, "SHA256", "signature algorithm for the certificate")
cmd.Flags().StringP(cmdFlagNameCommonName, "c", "", "certificate common name")
cmd.Flags().StringSliceP(cmdFlagNameOrganization, "o", []string{"Authelia"}, "certificate organization")
cmd.Flags().StringSlice(cmdFlagNameOrganizationalUnit, nil, "certificate organizational unit")
cmd.Flags().StringSlice(cmdFlagNameCountry, nil, "certificate country")
cmd.Flags().StringSlice(cmdFlagNameProvince, nil, "certificate province")
cmd.Flags().StringSliceP(cmdFlagNameLocality, "l", nil, "certificate locality")
cmd.Flags().StringSliceP(cmdFlagNameStreetAddress, "s", nil, "certificate street address")
cmd.Flags().StringSliceP(cmdFlagNamePostcode, "p", nil, "certificate postcode")
cmd.Flags().String(cmdFlagNameNotBefore, "", fmt.Sprintf("earliest date and time the certificate is considered valid formatted as %s (default is now)", timeLayoutCertificateNotBefore))
cmd.Flags().Duration(cmdFlagNameDuration, 365*24*time.Hour, "duration of time the certificate is valid for")
cmd.Flags().StringSlice(cmdFlagNameSANs, nil, "subject alternative names")
}
func cmdFlagsCryptoCertificateGenerate(cmd *cobra.Command) {
cmd.Flags().String(cmdFlagNamePathCA, "", "source directory of the certificate authority files, if not provided the certificate will be self-signed")
cmd.Flags().String(cmdFlagNameFileCAPrivateKey, "ca.private.pem", "certificate authority private key to use to signing this certificate")
cmd.Flags().String(cmdFlagNameFileCACertificate, "ca.public.crt", "certificate authority certificate to use when signing this certificate")
cmd.Flags().String(cmdFlagNameFileCertificate, "public.crt", "name of the file to export the certificate data to")
cmd.Flags().StringSlice(cmdFlagNameExtendedUsage, nil, "specify the extended usage types of the certificate")
cmd.Flags().Bool(cmdFlagNameCA, false, "create the certificate as a certificate authority certificate")
}
func cmdFlagsCryptoCertificateRequest(cmd *cobra.Command) {
cmd.Flags().String(cmdFlagNameFileCSR, "request.csr", "name of the file to export the certificate request data to")
}
func cmdFlagsCryptoPairGenerate(cmd *cobra.Command) {
cmd.Flags().String(cmdFlagNameFilePublicKey, "public.pem", "name of the file to export the public key data to")
cmd.Flags().Bool(cmdFlagNamePKCS8, false, "force PKCS #8 ASN.1 format")
}
func cmdFlagsCryptoPrivateKey(cmd *cobra.Command) {
cmd.Flags().String(cmdFlagNameFilePrivateKey, "private.pem", "name of the file to export the private key data to")
cmd.Flags().StringP(cmdFlagNameDirectory, "d", "", "directory where the generated keys, certificates, etc will be stored")
}
func cmdFlagsCryptoPrivateKeyRSA(cmd *cobra.Command) {
cmd.Flags().IntP(cmdFlagNameBits, "b", 2048, "number of RSA bits for the certificate")
}
func cmdFlagsCryptoPrivateKeyECDSA(cmd *cobra.Command) {
cmd.Flags().StringP(cmdFlagNameCurve, "b", "P256", "Sets the elliptic curve which can be P224, P256, P384, or P521")
}
func cmdFlagsCryptoPrivateKeyEd25519(cmd *cobra.Command) {
}
func cryptoSANsToString(dnsSANs []string, ipSANs []net.IP) (sans []string) {
sans = make([]string, len(dnsSANs)+len(ipSANs))
j := 0
for i, dnsSAN := range dnsSANs {
sans[j] = fmt.Sprintf("DNS.%d:%s", i+1, dnsSAN)
j++
}
for i, ipSAN := range ipSANs {
sans[j] = fmt.Sprintf("IP.%d:%s", i+1, ipSAN)
j++
}
return sans
}
func cryptoGetWritePathsFromCmd(cmd *cobra.Command) (privateKey, publicKey string, err error) {
var dir string
if dir, err = cmd.Flags().GetString(cmdFlagNameDirectory); err != nil {
return "", "", err
}
ca, _ := cmd.Flags().GetBool(cmdFlagNameCA)
csr := cmd.Use == cmdUseRequest
var private, public string
var flagPrivate, flagPublic string
switch {
case ca && csr:
flagPrivate, flagPublic = cmdFlagNameFileCAPrivateKey, cmdFlagNameFileCSR
case csr:
flagPrivate, flagPublic = cmdFlagNameFilePrivateKey, cmdFlagNameFileCSR
case ca:
flagPrivate, flagPublic = cmdFlagNameFileCAPrivateKey, cmdFlagNameFileCACertificate
case cmd.Parent().Parent().Use == cmdUsePair:
flagPrivate, flagPublic = cmdFlagNameFilePrivateKey, cmdFlagNameFilePublicKey
default:
flagPrivate, flagPublic = cmdFlagNameFilePrivateKey, cmdFlagNameFileCertificate
}
if private, err = cmd.Flags().GetString(flagPrivate); err != nil {
return "", "", err
}
if public, err = cmd.Flags().GetString(flagPublic); err != nil {
return "", "", err
}
return filepath.Join(dir, private), filepath.Join(dir, public), nil
}
func cryptoGenPrivateKeyFromCmd(cmd *cobra.Command) (privateKey interface{}, err error) {
switch cmd.Parent().Use {
case cmdUseRSA:
var (
bits int
)
if bits, err = cmd.Flags().GetInt(cmdFlagNameBits); err != nil {
return nil, err
}
if privateKey, err = rsa.GenerateKey(rand.Reader, bits); err != nil {
return nil, fmt.Errorf("generating RSA private key resulted in an error: %w", err)
}
case cmdUseECDSA:
var (
curveStr string
curve elliptic.Curve
)
if curveStr, err = cmd.Flags().GetString(cmdFlagNameCurve); err != nil {
return nil, err
}
if curve = utils.EllipticCurveFromString(curveStr); curve == nil {
return nil, fmt.Errorf("invalid curve '%s' was specified: curve must be P224, P256, P384, or P521", curveStr)
}
if privateKey, err = ecdsa.GenerateKey(curve, rand.Reader); err != nil {
return nil, fmt.Errorf("generating ECDSA private key resulted in an error: %w", err)
}
case cmdUseEd25519:
if _, privateKey, err = ed25519.GenerateKey(rand.Reader); err != nil {
return nil, fmt.Errorf("generating Ed25519 private key resulted in an error: %w", err)
}
}
return privateKey, nil
}
func cryptoGetCAFromCmd(cmd *cobra.Command) (privateKey interface{}, cert *x509.Certificate, err error) {
if !cmd.Flags().Changed(cmdFlagNamePathCA) {
return nil, nil, nil
}
var (
dir, filePrivateKey, fileCertificate string
ok bool
certificate interface{}
)
if dir, err = cmd.Flags().GetString(cmdFlagNamePathCA); err != nil {
return nil, nil, err
}
if filePrivateKey, err = cmd.Flags().GetString(cmdFlagNameFileCAPrivateKey); err != nil {
return nil, nil, err
}
if fileCertificate, err = cmd.Flags().GetString(cmdFlagNameFileCACertificate); err != nil {
return nil, nil, err
}
var (
bytesPrivateKey, bytesCertificate []byte
)
pathPrivateKey := filepath.Join(dir, filePrivateKey)
if bytesPrivateKey, err = os.ReadFile(pathPrivateKey); err != nil {
return nil, nil, fmt.Errorf("could not read private key file '%s': %w", pathPrivateKey, err)
}
if privateKey, err = utils.ParseX509FromPEM(bytesPrivateKey); err != nil {
return nil, nil, fmt.Errorf("could not parse private key from file '%s': %w", pathPrivateKey, err)
}
if privateKey == nil || !utils.IsX509PrivateKey(privateKey) {
return nil, nil, fmt.Errorf("could not parse private key from file '%s': does not appear to be a private key", pathPrivateKey)
}
pathCertificate := filepath.Join(dir, fileCertificate)
if bytesCertificate, err = os.ReadFile(pathCertificate); err != nil {
return nil, nil, fmt.Errorf("could not read certificate file '%s': %w", pathCertificate, err)
}
if certificate, err = utils.ParseX509FromPEM(bytesCertificate); err != nil {
return nil, nil, fmt.Errorf("could not parse certificate from file '%s': %w", pathCertificate, err)
}
if cert, ok = utils.CastX509AsCertificate(certificate); !ok {
return nil, nil, fmt.Errorf("could not parse certificate from file '%s': does not appear to be a certificate", pathCertificate)
}
return privateKey, cert, nil
}
func cryptoGetCSRFromCmd(cmd *cobra.Command) (csr *x509.CertificateRequest, err error) {
var (
subject *pkix.Name
dnsSANs []string
ipSANs []net.IP
)
if subject, err = cryptoGetSubjectFromCmd(cmd); err != nil {
return nil, err
}
keyAlg, sigAlg := cryptoGetAlgFromCmd(cmd)
if dnsSANs, ipSANs, err = cryptoGetSANsFromCmd(cmd); err != nil {
return nil, err
}
csr = &x509.CertificateRequest{
Subject: *subject,
PublicKeyAlgorithm: keyAlg,
SignatureAlgorithm: sigAlg,
DNSNames: dnsSANs,
IPAddresses: ipSANs,
}
return csr, nil
}
func cryptoGetSANsFromCmd(cmd *cobra.Command) (dnsSANs []string, ipSANs []net.IP, err error) {
var (
sans []string
)
if sans, err = cmd.Flags().GetStringSlice(cmdFlagNameSANs); err != nil {
return nil, nil, err
}
for _, san := range sans {
if ipSAN := net.ParseIP(san); ipSAN != nil {
ipSANs = append(ipSANs, ipSAN)
continue
}
dnsSANs = append(dnsSANs, san)
}
return dnsSANs, ipSANs, nil
}
func cryptoGetAlgFromCmd(cmd *cobra.Command) (keyAlg x509.PublicKeyAlgorithm, sigAlg x509.SignatureAlgorithm) {
sigAlgStr, _ := cmd.Flags().GetString(cmdFlagNameSignature)
keyAlgStr := cmd.Parent().Use
return utils.KeySigAlgorithmFromString(keyAlgStr, sigAlgStr)
}
func cryptoGetSubjectFromCmd(cmd *cobra.Command) (subject *pkix.Name, err error) {
var (
commonName string
organization, organizationalUnit, country, locality, province, streetAddress, postcode []string
)
if commonName, err = cmd.Flags().GetString(cmdFlagNameCommonName); err != nil {
return nil, err
}
if organization, err = cmd.Flags().GetStringSlice(cmdFlagNameOrganization); err != nil {
return nil, err
}
if organizationalUnit, err = cmd.Flags().GetStringSlice(cmdFlagNameOrganizationalUnit); err != nil {
return nil, err
}
if country, err = cmd.Flags().GetStringSlice(cmdFlagNameCountry); err != nil {
return nil, err
}
if locality, err = cmd.Flags().GetStringSlice(cmdFlagNameLocality); err != nil {
return nil, err
}
if province, err = cmd.Flags().GetStringSlice(cmdFlagNameProvince); err != nil {
return nil, err
}
if streetAddress, err = cmd.Flags().GetStringSlice(cmdFlagNameStreetAddress); err != nil {
return nil, err
}
if postcode, err = cmd.Flags().GetStringSlice(cmdFlagNamePostcode); err != nil {
return nil, err
}
return &pkix.Name{
CommonName: commonName,
Organization: organization,
OrganizationalUnit: organizationalUnit,
Country: country,
Locality: locality,
Province: province,
StreetAddress: streetAddress,
PostalCode: postcode,
}, nil
}
func cryptoGetCertificateFromCmd(cmd *cobra.Command) (certificate *x509.Certificate, err error) {
var (
ca bool
subject *pkix.Name
notBeforeStr string
duration time.Duration
)
if ca, err = cmd.Flags().GetBool(cmdFlagNameCA); err != nil {
return nil, err
}
if subject, err = cryptoGetSubjectFromCmd(cmd); err != nil {
return nil, err
}
if notBeforeStr, err = cmd.Flags().GetString(cmdFlagNameNotBefore); err != nil {
return nil, err
}
if duration, err = cmd.Flags().GetDuration(cmdFlagNameDuration); err != nil {
return nil, err
}
var (
notBefore time.Time
serialNumber *big.Int
dnsSANs, extKeyUsages []string
ipSANs []net.IP
)
switch len(notBeforeStr) {
case 0:
notBefore = time.Now()
default:
if notBefore, err = time.Parse(timeLayoutCertificateNotBefore, notBeforeStr); err != nil {
return nil, fmt.Errorf("failed to parse not before: %w", err)
}
}
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
if serialNumber, err = rand.Int(rand.Reader, serialNumberLimit); err != nil {
return nil, fmt.Errorf("failed to generate serial number: %w", err)
}
if dnsSANs, ipSANs, err = cryptoGetSANsFromCmd(cmd); err != nil {
return nil, err
}
keyAlg, sigAlg := cryptoGetAlgFromCmd(cmd)
if extKeyUsages, err = cmd.Flags().GetStringSlice(cmdFlagNameExtendedUsage); err != nil {
return nil, err
}
certificate = &x509.Certificate{
SerialNumber: serialNumber,
Subject: *subject,
NotBefore: notBefore,
NotAfter: notBefore.Add(duration),
IsCA: ca,
KeyUsage: utils.X509ParseKeyUsage(nil, ca),
ExtKeyUsage: utils.X509ParseExtendedKeyUsage(extKeyUsages, ca),
PublicKeyAlgorithm: keyAlg,
SignatureAlgorithm: sigAlg,
DNSNames: dnsSANs,
IPAddresses: ipSANs,
BasicConstraintsValid: true,
}
return certificate, nil
}
func fmtCryptoUse(use string) string {
switch use {
case cmdUseEd25519:
return "Ed25519"
default:
return strings.ToUpper(use)
}
}

View File

@ -36,9 +36,8 @@ func NewRootCmd() (cmd *cobra.Command) {
cmd.AddCommand(
newBuildInfoCmd(),
newCertificatesCmd(),
newCryptoCmd(),
newHashPasswordCmd(),
NewRSACmd(),
newStorageCmd(),
newValidateConfigCmd(),
newAccessControlCommand(),

View File

@ -1,110 +0,0 @@
package commands
import (
"fmt"
"os"
"path/filepath"
"github.com/spf13/cobra"
"github.com/authelia/authelia/v4/internal/utils"
)
// NewRSACmd returns a new RSA Cmd.
func NewRSACmd() (cmd *cobra.Command) {
cmd = &cobra.Command{
Use: "rsa",
Short: cmdAutheliaRSAShort,
Long: cmdAutheliaRSALong,
Example: cmdAutheliaRSAExample,
Args: cobra.NoArgs,
}
cmd.AddCommand(newRSAGenerateCmd())
return cmd
}
func newRSAGenerateCmd() (cmd *cobra.Command) {
cmd = &cobra.Command{
Use: "generate",
Short: cmdAutheliaRSAGenerateShort,
Long: cmdAutheliaRSAGenerateLong,
Example: cmdAutheliaRSAGenerateExample,
Args: cobra.NoArgs,
Run: cmdRSAGenerateRun,
}
cmd.Flags().StringP("dir", "d", "", "Target directory where the keypair will be stored")
cmd.Flags().IntP("key-size", "b", 2048, "Sets the key size in bits")
return cmd
}
func cmdRSAGenerateRun(cmd *cobra.Command, _ []string) {
bits, err := cmd.Flags().GetInt("key-size")
if err != nil {
fmt.Printf("Failed to parse key-size flag: %v\n", err)
return
}
privateKey, publicKey := utils.GenerateRsaKeyPair(bits)
rsaTargetDirectory, err := cmd.Flags().GetString("dir")
if err != nil {
fmt.Printf("Failed to parse dir flag: %v\n", err)
return
}
keyPath := filepath.Join(rsaTargetDirectory, "key.pem")
keyOut, err := os.OpenFile(keyPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
fmt.Printf("Failed to open %s for writing: %v\n", keyPath, err)
return
}
defer func() {
if err := keyOut.Close(); err != nil {
fmt.Printf("Unable to close private key file: %v\n", err)
os.Exit(1)
}
}()
_, err = keyOut.WriteString(utils.ExportRsaPrivateKeyAsPemStr(privateKey))
if err != nil {
fmt.Printf("Failed to write private key: %v\n", err)
return
}
fmt.Printf("RSA Private Key written to %s\n", keyPath)
certPath := filepath.Join(rsaTargetDirectory, "key.pub")
certOut, err := os.OpenFile(certPath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
fmt.Printf("Failed to open %s for writing: %v\n", keyPath, err)
return
}
defer func() {
if err := certOut.Close(); err != nil {
fmt.Printf("Failed to close public key file: %v\n", err)
os.Exit(1)
}
}()
publicPem, err := utils.ExportRsaPublicKeyAsPemStr(publicKey)
if err != nil {
fmt.Printf("Failed to marshal public key: %v\n", err)
return
}
_, err = certOut.WriteString(publicPem)
if err != nil {
fmt.Printf("Failed to write private key: %v\n", err)
return
}
fmt.Printf("RSA Public Key written to %s\n", certPath)
}

View File

@ -86,11 +86,17 @@ func (m KeyManager) GetActivePrivateKey() (key *rsa.PrivateKey, err error) {
// AddActivePrivateKeyData adds a rsa.PublicKey given the key in the PEM string format, then sets it to the active key.
func (m *KeyManager) AddActivePrivateKeyData(data string) (key *rsa.PrivateKey, webKey *jose.JSONWebKey, err error) {
key, err = utils.ParseRsaPrivateKeyFromPemStr(data)
ikey, err := utils.ParseX509FromPEM([]byte(data))
if err != nil {
return nil, nil, err
}
var ok bool
if key, ok = ikey.(*rsa.PrivateKey); !ok {
return nil, nil, errors.New("key must be an RSA private key")
}
webKey, err = m.AddActivePrivateKey(key)
return key, webKey, err

View File

@ -1,6 +1,7 @@
package suites
import (
"bytes"
"context"
"fmt"
"os"
@ -13,6 +14,7 @@ import (
"github.com/authelia/authelia/v4/internal/model"
"github.com/authelia/authelia/v4/internal/storage"
"github.com/authelia/authelia/v4/internal/utils"
)
type CLISuite struct {
@ -37,7 +39,7 @@ func (s *CLISuite) SetupTest() {
coverageArg := ""
if os.Getenv("CI") == t {
testArg = "-test.coverprofile=/authelia/coverage-$(date +%s).txt"
testArg = "-test.coverprofile=/authelia/coverage-$(cat /proc/sys/kernel/random/uuid).txt"
coverageArg = "COVERAGE"
}
@ -94,79 +96,526 @@ func (s *CLISuite) TestShouldHashPasswordSHA512() {
s.Assert().Contains(output, "Password hash: $6$rounds=50000")
}
func (s *CLISuite) TestShouldGenerateCertificateRSA() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "certificates", "generate", "--host=*.example.com", "--dir=/tmp/"})
func (s *CLISuite) TestShouldGenerateRSACertificateRequest() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "rsa", "request", "--common-name=example.com", "--sans='*.example.com'", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Certificate written to /tmp/cert.pem")
s.Assert().Contains(output, "Private Key written to /tmp/key.pem")
s.Assert().Contains(output, "Generating Certificate Request")
s.Assert().Contains(output, "\tCommon Name: example.com, Organization: [Authelia], Organizational Unit: []")
s.Assert().Contains(output, "\tCountry: [], Province: [], Street Address: [], Postal Code: [], Locality: []")
s.Assert().Contains(output, "\tSignature Algorithm: SHA256-RSA, Public Key Algorithm: RSA, Bits: 2048")
s.Assert().Contains(output, "\tSubject Alternative Names: DNS.1:*.example.com")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tCertificate Request: /tmp/request.csr")
}
func (s *CLISuite) TestShouldGenerateECDSACurveP224CertificateRequest() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "ecdsa", "request", "--curve=P224", "--common-name=example.com", "--sans='*.example.com'", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Generating Certificate Request")
s.Assert().Contains(output, "\tCommon Name: example.com, Organization: [Authelia], Organizational Unit: []")
s.Assert().Contains(output, "\tCountry: [], Province: [], Street Address: [], Postal Code: [], Locality: []")
s.Assert().Contains(output, "\tSignature Algorithm: ECDSA-SHA256, Public Key Algorithm: ECDSA, Elliptic Curve: P-224")
s.Assert().Contains(output, "\tSubject Alternative Names: DNS.1:*.example.com")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tCertificate Request: /tmp/request.csr")
}
func (s *CLISuite) TestShouldGenerateECDSACurveP256CertificateRequest() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "ecdsa", "request", "--curve=P256", "--common-name=example.com", "--sans='*.example.com'", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Generating Certificate Request")
s.Assert().Contains(output, "\tCommon Name: example.com, Organization: [Authelia], Organizational Unit: []")
s.Assert().Contains(output, "\tCountry: [], Province: [], Street Address: [], Postal Code: [], Locality: []")
s.Assert().Contains(output, "\tSignature Algorithm: ECDSA-SHA256, Public Key Algorithm: ECDSA, Elliptic Curve: P-256")
s.Assert().Contains(output, "\tSubject Alternative Names: DNS.1:*.example.com")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tCertificate Request: /tmp/request.csr")
}
func (s *CLISuite) TestShouldGenerateECDSACurveP384CertificateRequest() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "ecdsa", "request", "--curve=P384", "--common-name=example.com", "--sans='*.example.com'", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Generating Certificate Request")
s.Assert().Contains(output, "\tCommon Name: example.com, Organization: [Authelia], Organizational Unit: []")
s.Assert().Contains(output, "\tCountry: [], Province: [], Street Address: [], Postal Code: [], Locality: []")
s.Assert().Contains(output, "\tSignature Algorithm: ECDSA-SHA256, Public Key Algorithm: ECDSA, Elliptic Curve: P-384")
s.Assert().Contains(output, "\tSubject Alternative Names: DNS.1:*.example.com")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tCertificate Request: /tmp/request.csr")
}
func (s *CLISuite) TestShouldGenerateECDSACurveP521CertificateRequest() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "ecdsa", "request", "--curve=P521", "--common-name=example.com", "--sans='*.example.com'", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Generating Certificate Request")
s.Assert().Contains(output, "\tCommon Name: example.com, Organization: [Authelia], Organizational Unit: []")
s.Assert().Contains(output, "\tCountry: [], Province: [], Street Address: [], Postal Code: [], Locality: []")
s.Assert().Contains(output, "\tSignature Algorithm: ECDSA-SHA256, Public Key Algorithm: ECDSA, Elliptic Curve: P-521")
s.Assert().Contains(output, "\tSubject Alternative Names: DNS.1:*.example.com")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tCertificate Request: /tmp/request.csr")
}
func (s *CLISuite) TestShouldGenerateEd25519CertificateRequest() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "ed25519", "request", "--common-name=example.com", "--sans='*.example.com'", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Generating Certificate Request")
s.Assert().Contains(output, "\tCommon Name: example.com, Organization: [Authelia], Organizational Unit: []")
s.Assert().Contains(output, "\tCountry: [], Province: [], Street Address: [], Postal Code: [], Locality: []")
s.Assert().Contains(output, "\tSignature Algorithm: Ed25519, Public Key Algorithm: Ed25519")
s.Assert().Contains(output, "\tSubject Alternative Names: DNS.1:*.example.com")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tCertificate Request: /tmp/request.csr")
}
func (s *CLISuite) TestShouldGenerateCertificateRSA() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "rsa", "generate", "--common-name=example.com", "--sans='*.example.com'", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Generating Certificate")
s.Assert().Contains(output, "\tSerial: ")
s.Assert().Contains(output, "Signed By:\n\tSelf-Signed")
s.Assert().Contains(output, "\tCommon Name: example.com, Organization: [Authelia], Organizational Unit: []")
s.Assert().Contains(output, "\tCountry: [], Province: [], Street Address: [], Postal Code: [], Locality: []")
s.Assert().Contains(output, "\tCA: false, CSR: false, Signature Algorithm: SHA256-RSA, Public Key Algorithm: RSA, Bits: 2048")
s.Assert().Contains(output, "\tSubject Alternative Names: DNS.1:*.example.com")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tCertificate: /tmp/public.crt")
}
func (s *CLISuite) TestShouldGenerateCertificateRSAWithIPAddress() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "certificates", "generate", "--host=127.0.0.1", "--dir=/tmp/"})
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "rsa", "generate", "--common-name=example.com", "--sans", "*.example.com,127.0.0.1", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Certificate written to /tmp/cert.pem")
s.Assert().Contains(output, "Private Key written to /tmp/key.pem")
s.Assert().Contains(output, "Generating Certificate")
s.Assert().Contains(output, "\tSerial: ")
s.Assert().Contains(output, "Signed By:\n\tSelf-Signed")
s.Assert().Contains(output, "\tCommon Name: example.com, Organization: [Authelia], Organizational Unit: []")
s.Assert().Contains(output, "\tCountry: [], Province: [], Street Address: [], Postal Code: [], Locality: []")
s.Assert().Contains(output, "\tCA: false, CSR: false, Signature Algorithm: SHA256-RSA, Public Key Algorithm: RSA, Bits: 2048")
s.Assert().Contains(output, "\tSubject Alternative Names: DNS.1:*.example.com, IP.1:127.0.0.1")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tCertificate: /tmp/public.crt")
}
func (s *CLISuite) TestShouldGenerateCertificateRSAWithStartDate() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "certificates", "generate", "--host=*.example.com", "--dir=/tmp/", "--start-date='Jan 1 15:04:05 2011'"})
func (s *CLISuite) TestShouldGenerateCertificateRSAWithNotBefore() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "rsa", "generate", "--common-name=example.com", "--sans='*.example.com'", "--not-before", "'Jan 1 15:04:05 2011'", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Certificate written to /tmp/cert.pem")
s.Assert().Contains(output, "Private Key written to /tmp/key.pem")
s.Assert().Contains(output, "Generating Certificate")
s.Assert().Contains(output, "\tSerial: ")
s.Assert().Contains(output, "Signed By:\n\tSelf-Signed")
s.Assert().Contains(output, "\tCommon Name: example.com, Organization: [Authelia], Organizational Unit: []")
s.Assert().Contains(output, "\tCountry: [], Province: [], Street Address: [], Postal Code: [], Locality: []")
s.Assert().Contains(output, "\tNot Before: 2011-01-01T15:04:05Z, Not After: 2012-01-01T15:04:05Z")
s.Assert().Contains(output, "\tCA: false, CSR: false, Signature Algorithm: SHA256-RSA, Public Key Algorithm: RSA, Bits: 2048")
s.Assert().Contains(output, "\tSubject Alternative Names: DNS.1:*.example.com")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tCertificate: /tmp/public.crt")
}
func (s *CLISuite) TestShouldFailGenerateCertificateRSAWithStartDate() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "certificates", "generate", "--host=*.example.com", "--dir=/tmp/", "--start-date=Jan"})
func (s *CLISuite) TestShouldFailGenerateCertificateRSAWithInvalidNotBefore() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "rsa", "generate", "--common-name=example.com", "--sans='*.example.com'", "--not-before", "Jan", "--directory=/tmp/"})
s.Assert().NotNil(err)
s.Assert().Contains(output, "Failed to parse start date: parsing time \"Jan\" as \"Jan 2 15:04:05 2006\": cannot parse \"\" as \"2\"")
s.Assert().Contains(output, "Error: failed to parse not before: parsing time \"Jan\" as \"Jan 2 15:04:05 2006\": cannot parse \"\" as \"2\"")
}
func (s *CLISuite) TestShouldGenerateCertificateRSAWith4096Bits() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "rsa", "generate", "--bits=4096", "--common-name=example.com", "--sans='*.example.com'", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Generating Certificate")
s.Assert().Contains(output, "\tSerial: ")
s.Assert().Contains(output, "Signed By:\n\tSelf-Signed")
s.Assert().Contains(output, "\tCommon Name: example.com, Organization: [Authelia], Organizational Unit: []")
s.Assert().Contains(output, "\tCountry: [], Province: [], Street Address: [], Postal Code: [], Locality: []")
s.Assert().Contains(output, "\tCA: false, CSR: false, Signature Algorithm: SHA256-RSA, Public Key Algorithm: RSA, Bits: 4096")
s.Assert().Contains(output, "\tSubject Alternative Names: DNS.1:*.example.com")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tCertificate: /tmp/public.crt")
}
func (s *CLISuite) TestShouldGenerateCertificateWithCustomizedSubject() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "rsa", "generate", "--common-name=example.com", "--sans='*.example.com'", "--country=Australia", "--organization='Acme Co.'", "--organizational-unit=Tech", "--province=QLD", "--street-address='123 Smith St'", "--postcode=4000", "--locality=Internet", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Generating Certificate")
s.Assert().Contains(output, "\tSerial: ")
s.Assert().Contains(output, "Signed By:\n\tSelf-Signed")
s.Assert().Contains(output, "\tCommon Name: example.com, Organization: [Acme Co.], Organizational Unit: [Tech]")
s.Assert().Contains(output, "\tCountry: [Australia], Province: [QLD], Street Address: [123 Smith St], Postal Code: [4000], Locality: [Internet]")
s.Assert().Contains(output, "\tCA: false, CSR: false, Signature Algorithm: SHA256-RSA, Public Key Algorithm: RSA, Bits: 2048")
s.Assert().Contains(output, "\tSubject Alternative Names: DNS.1:*.example.com")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tCertificate: /tmp/public.crt")
}
func (s *CLISuite) TestShouldGenerateCertificateCA() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "certificates", "generate", "--host=*.example.com", "--dir=/tmp/", "--ca"})
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "rsa", "generate", "--common-name='Authelia Standalone Root Certificate Authority'", "--ca", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Generating Certificate")
s.Assert().Contains(output, "\tSerial: ")
s.Assert().Contains(output, "Signed By:\n\tSelf-Signed")
s.Assert().Contains(output, "\tCommon Name: Authelia Standalone Root Certificate Authority, Organization: [Authelia], Organizational Unit: []")
s.Assert().Contains(output, "\tCountry: [], Province: [], Street Address: [], Postal Code: [], Locality: []")
s.Assert().Contains(output, "\tCA: true, CSR: false, Signature Algorithm: SHA256-RSA, Public Key Algorithm: RSA, Bits: 2048")
s.Assert().Contains(output, "\tSubject Alternative Names: ")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/ca.private.pem")
s.Assert().Contains(output, "\tCertificate: /tmp/ca.public.crt")
}
func (s *CLISuite) TestShouldGenerateCertificateCAAndSignCertificate() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "rsa", "generate", "--common-name='Authelia Standalone Root Certificate Authority'", "--ca", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Generating Certificate")
s.Assert().Contains(output, "\tSerial: ")
s.Assert().Contains(output, "Signed By:\n\tSelf-Signed")
s.Assert().Contains(output, "\tCommon Name: Authelia Standalone Root Certificate Authority, Organization: [Authelia], Organizational Unit: []")
s.Assert().Contains(output, "\tCountry: [], Province: [], Street Address: [], Postal Code: [], Locality: []")
s.Assert().Contains(output, "\tCA: true, CSR: false, Signature Algorithm: SHA256-RSA, Public Key Algorithm: RSA, Bits: 2048")
s.Assert().Contains(output, "\tSubject Alternative Names: ")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/ca.private.pem")
s.Assert().Contains(output, "\tCertificate: /tmp/ca.public.crt")
output, err = s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "rsa", "generate", "--common-name=example.com", "--sans='*.example.com'", "--path.ca", "/tmp/", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Generating Certificate")
s.Assert().Contains(output, "\tSerial: ")
s.Assert().Contains(output, "Signed By:\n\tAuthelia Standalone Root Certificate Authority")
s.Assert().Contains(output, "\tSerial: ")
s.Assert().Contains(output, ", Expires: ")
s.Assert().Contains(output, "\tCommon Name: example.com, Organization: [Authelia], Organizational Unit: []")
s.Assert().Contains(output, "\tCountry: [], Province: [], Street Address: [], Postal Code: [], Locality: []")
s.Assert().Contains(output, "\tCA: false, CSR: false, Signature Algorithm: SHA256-RSA, Public Key Algorithm: RSA, Bits: 2048")
s.Assert().Contains(output, "\tSubject Alternative Names: DNS.1:*.example.com")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tCertificate: /tmp/public.crt")
// Check the certificates look fine.
privateKeyData, err := os.ReadFile("/tmp/private.pem")
s.Assert().NoError(err)
certificateData, err := os.ReadFile("/tmp/public.crt")
s.Assert().NoError(err)
privateKeyCAData, err := os.ReadFile("/tmp/ca.private.pem")
s.Assert().NoError(err)
certificateCAData, err := os.ReadFile("/tmp/ca.public.crt")
s.Assert().NoError(err)
s.Assert().False(bytes.Equal(privateKeyData, privateKeyCAData))
s.Assert().False(bytes.Equal(certificateData, certificateCAData))
privateKey, err := utils.ParseX509FromPEM(privateKeyData)
s.Assert().NoError(err)
s.Assert().True(utils.IsX509PrivateKey(privateKey))
privateCAKey, err := utils.ParseX509FromPEM(privateKeyCAData)
s.Assert().NoError(err)
s.Assert().True(utils.IsX509PrivateKey(privateCAKey))
c, err := utils.ParseX509FromPEM(certificateData)
s.Assert().NoError(err)
s.Assert().False(utils.IsX509PrivateKey(c))
cCA, err := utils.ParseX509FromPEM(certificateCAData)
s.Assert().NoError(err)
s.Assert().False(utils.IsX509PrivateKey(cCA))
certificate, ok := utils.CastX509AsCertificate(c)
s.Assert().True(ok)
certificateCA, ok := utils.CastX509AsCertificate(cCA)
s.Assert().True(ok)
s.Require().NotNil(certificate)
s.Require().NotNil(certificateCA)
err = certificate.CheckSignatureFrom(certificateCA)
s.Assert().NoError(err)
s.Assert().Contains(output, "Certificate written to /tmp/cert.pem")
s.Assert().Contains(output, "Private Key written to /tmp/key.pem")
}
func (s *CLISuite) TestShouldGenerateCertificateEd25519() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "certificates", "generate", "--host=*.example.com", "--dir=/tmp/", "--ed25519"})
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "ed25519", "generate", "--common-name=example.com", "--sans='*.example.com'", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Certificate written to /tmp/cert.pem")
s.Assert().Contains(output, "Private Key written to /tmp/key.pem")
s.Assert().Contains(output, "Generating Certificate")
s.Assert().Contains(output, "\tSerial: ")
s.Assert().Contains(output, "Signed By:\n\tSelf-Signed")
s.Assert().Contains(output, "\tCommon Name: example.com, Organization: [Authelia], Organizational Unit: []")
s.Assert().Contains(output, "\tCountry: [], Province: [], Street Address: [], Postal Code: [], Locality: []")
s.Assert().Contains(output, "\tCA: false, CSR: false, Signature Algorithm: Ed25519, Public Key Algorithm: Ed25519")
s.Assert().Contains(output, "\tSubject Alternative Names: DNS.1:*.example.com")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tCertificate: /tmp/public.crt")
}
func (s *CLISuite) TestShouldFailGenerateCertificateParseNotBefore() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "ecdsa", "generate", "--not-before=invalid", "--common-name=example.com", "--sans='*.example.com'", "--directory=/tmp/"})
s.Assert().NotNil(err)
s.Assert().Contains(output, "Error: failed to parse not before: parsing time \"invalid\" as \"Jan 2 15:04:05 2006\": cannot parse \"invalid\" as \"Jan\"")
}
func (s *CLISuite) TestShouldFailGenerateCertificateECDSA() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "certificates", "generate", "--host=*.example.com", "--dir=/tmp/", "--ecdsa-curve=invalid"})
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "ecdsa", "generate", "--curve=invalid", "--common-name=example.com", "--sans='*.example.com'", "--directory=/tmp/"})
s.Assert().NotNil(err)
s.Assert().Contains(output, "Failed to generate private key: unrecognized elliptic curve: \"invalid\"")
s.Assert().Contains(output, "Error: invalid curve 'invalid' was specified: curve must be P224, P256, P384, or P521")
}
func (s *CLISuite) TestShouldGenerateCertificateECDSAP224() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "certificates", "generate", "--host=*.example.com", "--dir=/tmp/", "--ecdsa-curve=P224"})
func (s *CLISuite) TestShouldGenerateCertificateECDSACurveP224() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "ecdsa", "generate", "--curve=P224", "--common-name=example.com", "--sans='*.example.com'", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Certificate written to /tmp/cert.pem")
s.Assert().Contains(output, "Private Key written to /tmp/key.pem")
s.Assert().Contains(output, "Generating Certificate")
s.Assert().Contains(output, "\tSerial: ")
s.Assert().Contains(output, "Signed By:\n\tSelf-Signed")
s.Assert().Contains(output, "\tCommon Name: example.com, Organization: [Authelia], Organizational Unit: []")
s.Assert().Contains(output, "\tCountry: [], Province: [], Street Address: [], Postal Code: [], Locality: []")
s.Assert().Contains(output, "\tCA: false, CSR: false, Signature Algorithm: ECDSA-SHA256, Public Key Algorithm: ECDSA, Elliptic Curve: P-224")
s.Assert().Contains(output, "\tSubject Alternative Names: DNS.1:*.example.com")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tCertificate: /tmp/public.crt")
}
func (s *CLISuite) TestShouldGenerateCertificateECDSAP256() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "certificates", "generate", "--host=*.example.com", "--dir=/tmp/", "--ecdsa-curve=P256"})
func (s *CLISuite) TestShouldGenerateCertificateECDSACurveP256() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "ecdsa", "generate", "--curve=P256", "--common-name=example.com", "--sans='*.example.com'", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Certificate written to /tmp/cert.pem")
s.Assert().Contains(output, "Private Key written to /tmp/key.pem")
s.Assert().Contains(output, "Generating Certificate")
s.Assert().Contains(output, "\tSerial: ")
s.Assert().Contains(output, "Signed By:\n\tSelf-Signed")
s.Assert().Contains(output, "\tCommon Name: example.com, Organization: [Authelia], Organizational Unit: []")
s.Assert().Contains(output, "\tCountry: [], Province: [], Street Address: [], Postal Code: [], Locality: []")
s.Assert().Contains(output, "\tCA: false, CSR: false, Signature Algorithm: ECDSA-SHA256, Public Key Algorithm: ECDSA, Elliptic Curve: P-256")
s.Assert().Contains(output, "\tSubject Alternative Names: DNS.1:*.example.com")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tCertificate: /tmp/public.crt")
}
func (s *CLISuite) TestShouldGenerateCertificateECDSAP384() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "certificates", "generate", "--host=*.example.com", "--dir=/tmp/", "--ecdsa-curve=P384"})
func (s *CLISuite) TestShouldGenerateCertificateECDSACurveP384() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "ecdsa", "generate", "--curve=P384", "--common-name=example.com", "--sans='*.example.com'", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Certificate written to /tmp/cert.pem")
s.Assert().Contains(output, "Private Key written to /tmp/key.pem")
s.Assert().Contains(output, "Generating Certificate")
s.Assert().Contains(output, "\tSerial: ")
s.Assert().Contains(output, "Signed By:\n\tSelf-Signed")
s.Assert().Contains(output, "\tCommon Name: example.com, Organization: [Authelia], Organizational Unit: []")
s.Assert().Contains(output, "\tCountry: [], Province: [], Street Address: [], Postal Code: [], Locality: []")
s.Assert().Contains(output, "\tCA: false, CSR: false, Signature Algorithm: ECDSA-SHA256, Public Key Algorithm: ECDSA, Elliptic Curve: P-384")
s.Assert().Contains(output, "\tSubject Alternative Names: DNS.1:*.example.com")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tCertificate: /tmp/public.crt")
}
func (s *CLISuite) TestShouldGenerateCertificateECDSAP521() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "certificates", "generate", "--host=*.example.com", "--dir=/tmp/", "--ecdsa-curve=P521"})
func (s *CLISuite) TestShouldGenerateCertificateECDSACurveP521() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "ecdsa", "generate", "--curve=P521", "--common-name=example.com", "--sans='*.example.com'", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Certificate written to /tmp/cert.pem")
s.Assert().Contains(output, "Private Key written to /tmp/key.pem")
s.Assert().Contains(output, "Generating Certificate")
s.Assert().Contains(output, "\tSerial: ")
s.Assert().Contains(output, "Signed By:\n\tSelf-Signed")
s.Assert().Contains(output, "\tCommon Name: example.com, Organization: [Authelia], Organizational Unit: []")
s.Assert().Contains(output, "\tCountry: [], Province: [], Street Address: [], Postal Code: [], Locality: []")
s.Assert().Contains(output, "\tCA: false, CSR: false, Signature Algorithm: ECDSA-SHA256, Public Key Algorithm: ECDSA, Elliptic Curve: P-521")
s.Assert().Contains(output, "\tSubject Alternative Names: DNS.1:*.example.com")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tCertificate: /tmp/public.crt")
}
func (s *CLISuite) TestShouldGenerateRSAKeyPair() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "pair", "rsa", "generate", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Generating key pair")
s.Assert().Contains(output, "Algorithm: RSA-256 2048 bits\n\n")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tPublic Key: /tmp/public.pem")
}
func (s *CLISuite) TestShouldGenerateRSAKeyPairWith4069Bits() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "pair", "rsa", "generate", "--bits=4096", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Generating key pair")
s.Assert().Contains(output, "Algorithm: RSA-512 4096 bits\n\n")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tPublic Key: /tmp/public.pem")
}
func (s *CLISuite) TestShouldGenerateECDSAKeyPair() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "pair", "ecdsa", "generate", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Generating key pair")
s.Assert().Contains(output, "Algorithm: ECDSA Curve P-256\n\n")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tPublic Key: /tmp/public.pem")
}
func (s *CLISuite) TestShouldGenerateECDSAKeyPairCurveP224() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "pair", "ecdsa", "generate", "--curve=P224", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Generating key pair")
s.Assert().Contains(output, "Algorithm: ECDSA Curve P-224\n\n")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tPublic Key: /tmp/public.pem")
}
func (s *CLISuite) TestShouldGenerateECDSAKeyPairCurveP256() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "pair", "ecdsa", "generate", "--curve=P256", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Generating key pair")
s.Assert().Contains(output, "Algorithm: ECDSA Curve P-256\n\n")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tPublic Key: /tmp/public.pem")
}
func (s *CLISuite) TestShouldGenerateECDSAKeyPairCurveP384() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "pair", "ecdsa", "generate", "--curve=P384", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Generating key pair")
s.Assert().Contains(output, "Algorithm: ECDSA Curve P-384\n\n")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tPublic Key: /tmp/public.pem")
}
func (s *CLISuite) TestShouldGenerateECDSAKeyPairCurveP521() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "pair", "ecdsa", "generate", "--curve=P521", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Generating key pair")
s.Assert().Contains(output, "Algorithm: ECDSA Curve P-521\n\n")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tPublic Key: /tmp/public.pem")
}
func (s *CLISuite) TestShouldGenerateEd25519KeyPair() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "pair", "ed25519", "generate", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Assert().Contains(output, "Generating key pair")
s.Assert().Contains(output, "Algorithm: Ed25519\n\n")
s.Assert().Contains(output, "Output Paths:")
s.Assert().Contains(output, "\tPrivate Key: /tmp/private.pem")
s.Assert().Contains(output, "\tPublic Key: /tmp/public.pem")
}
func (s *CLISuite) TestShouldNotGenerateECDSAKeyPairCurveInvalid() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "pair", "ecdsa", "generate", "--curve=invalid", "--directory=/tmp/"})
s.Assert().NotNil(err)
s.Assert().Contains(output, "Error: invalid curve 'invalid' was specified: curve must be P224, P256, P384, or P521")
}
func (s *CLISuite) TestShouldNotGenerateRSAWithBadCAPath() {
output, err := s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "rsa", "generate", "--path.ca=/tmp/invalid", "--directory=/tmp/"})
s.Assert().NotNil(err)
s.Assert().Contains(output, "Error: could not read private key file '/tmp/invalid/ca.private.pem': open /tmp/invalid/ca.private.pem: no such file or directory\n")
}
func (s *CLISuite) TestShouldNotGenerateRSAWithBadCAFileNames() {
var (
err error
output string
)
_, err = s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "rsa", "generate", "--common-name='Authelia Standalone Root Certificate Authority'", "--ca", "--directory=/tmp/"})
s.Assert().NoError(err)
output, err = s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "rsa", "generate", "--path.ca=/tmp/", "--file.ca-private-key=invalid.pem", "--directory=/tmp/"})
s.Assert().NotNil(err)
s.Assert().Contains(output, "Error: could not read private key file '/tmp/invalid.pem': open /tmp/invalid.pem: no such file or directory\n")
output, err = s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "rsa", "generate", "--path.ca=/tmp/", "--file.ca-certificate=invalid.crt", "--directory=/tmp/"})
s.Assert().NotNil(err)
s.Assert().Contains(output, "Error: could not read certificate file '/tmp/invalid.crt': open /tmp/invalid.crt: no such file or directory\n")
}
func (s *CLISuite) TestShouldNotGenerateRSAWithBadCAFileContent() {
var (
err error
output string
)
_, err = s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "rsa", "generate", "--common-name='Authelia Standalone Root Certificate Authority'", "--ca", "--directory=/tmp/"})
s.Assert().NoError(err)
s.Require().NoError(os.WriteFile("/tmp/ca.private.bad.pem", []byte("INVALID"), 0600)) //nolint:gosec
s.Require().NoError(os.WriteFile("/tmp/ca.public.bad.crt", []byte("INVALID"), 0600)) //nolint:gosec
output, err = s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "rsa", "generate", "--path.ca=/tmp/", "--file.ca-private-key=ca.private.bad.pem", "--directory=/tmp/"})
s.Assert().NotNil(err)
s.Assert().Contains(output, "Error: could not parse private key from file '/tmp/ca.private.bad.pem': failed to parse PEM block containing the key\n")
output, err = s.Exec("authelia-backend", []string{"authelia", s.testArg, s.coverageArg, "crypto", "certificate", "rsa", "generate", "--path.ca=/tmp/", "--file.ca-certificate=ca.public.bad.crt", "--directory=/tmp/"})
s.Assert().NotNil(err)
s.Assert().Contains(output, "Error: could not parse certificate from file '/tmp/ca.public.bad.crt': failed to parse PEM block containing the key\n")
}
func (s *CLISuite) TestStorageShouldShowErrWithoutConfig() {

View File

@ -8,9 +8,9 @@ import (
"path/filepath"
"runtime"
"strings"
"time"
"github.com/go-rod/rod"
"github.com/google/uuid"
)
// GetLoginBaseURL returns the URL of the login portal and the path prefix if specified.
@ -24,7 +24,6 @@ func GetLoginBaseURL() string {
func (rs *RodSession) collectCoverage(page *rod.Page) {
coverageDir := "../../web/.nyc_output"
now := time.Now()
resp, err := page.Eval("() => JSON.stringify(window.__coverage__)")
if err != nil {
@ -36,7 +35,7 @@ func (rs *RodSession) collectCoverage(page *rod.Page) {
_ = os.MkdirAll(coverageDir, 0775)
if coverageData != "<nil>" {
err = os.WriteFile(fmt.Sprintf("%s/coverage-%d.json", coverageDir, now.Unix()), []byte(coverageData), 0664) //nolint:gosec
err = os.WriteFile(fmt.Sprintf("%s/coverage-%s.json", coverageDir, uuid.New().String()), []byte(coverageData), 0664) //nolint:gosec
if err != nil {
log.Fatal(err)
}

View File

@ -1,253 +0,0 @@
package utils
import (
"bytes"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"math/big"
"net"
"os"
"path/filepath"
"strings"
"time"
"github.com/authelia/authelia/v4/internal/configuration/schema"
"github.com/authelia/authelia/v4/internal/logging"
)
// PEMBlockType represent an enum of the existing PEM block types.
type PEMBlockType int
const (
// Certificate block type.
Certificate PEMBlockType = iota
// PrivateKey block type.
PrivateKey
)
// NewTLSConfig generates a tls.Config from a schema.TLSConfig and a x509.CertPool.
func NewTLSConfig(config *schema.TLSConfig, defaultMinVersion uint16, certPool *x509.CertPool) (tlsConfig *tls.Config) {
minVersion, err := TLSStringToTLSConfigVersion(config.MinimumVersion)
if err != nil {
minVersion = defaultMinVersion
}
return &tls.Config{
ServerName: config.ServerName,
InsecureSkipVerify: config.SkipVerify, //nolint:gosec // Informed choice by user. Off by default.
MinVersion: minVersion,
RootCAs: certPool,
}
}
// NewX509CertPool generates a x509.CertPool from the system PKI and the directory specified.
func NewX509CertPool(directory string) (certPool *x509.CertPool, warnings []error, errors []error) {
certPool, err := x509.SystemCertPool()
if err != nil {
warnings = append(warnings, fmt.Errorf("could not load system certificate pool which may result in untrusted certificate issues: %v", err))
certPool = x509.NewCertPool()
}
logger := logging.Logger()
logger.Tracef("Starting scan of directory %s for certificates", directory)
if directory != "" {
certsFileInfo, err := os.ReadDir(directory)
if err != nil {
errors = append(errors, fmt.Errorf("could not read certificates from directory %v", err))
} else {
for _, certFileInfo := range certsFileInfo {
nameLower := strings.ToLower(certFileInfo.Name())
if !certFileInfo.IsDir() && (strings.HasSuffix(nameLower, ".cer") || strings.HasSuffix(nameLower, ".crt") || strings.HasSuffix(nameLower, ".pem")) {
certPath := filepath.Join(directory, certFileInfo.Name())
logger.Tracef("Found possible cert %s, attempting to add it to the pool", certPath)
certBytes, err := os.ReadFile(certPath)
if err != nil {
errors = append(errors, fmt.Errorf("could not read certificate %v", err))
} else if ok := certPool.AppendCertsFromPEM(certBytes); !ok {
errors = append(errors, fmt.Errorf("could not import certificate %s", certFileInfo.Name()))
}
}
}
}
}
logger.Tracef("Finished scan of directory %s for certificates", directory)
return certPool, warnings, errors
}
// TLSStringToTLSConfigVersion returns a go crypto/tls version for a tls.Config based on string input.
func TLSStringToTLSConfigVersion(input string) (version uint16, err error) {
switch strings.ToUpper(input) {
case "TLS1.3", TLS13:
return tls.VersionTLS13, nil
case "TLS1.2", TLS12:
return tls.VersionTLS12, nil
case "TLS1.1", TLS11:
return tls.VersionTLS11, nil
case "TLS1.0", TLS10:
return tls.VersionTLS10, nil
}
return 0, ErrTLSVersionNotSupported
}
// GenerateCertificate generate a certificate given a private key. RSA, Ed25519 and ECDSA are officially supported.
func GenerateCertificate(privateKeyBuilder PrivateKeyBuilder, hosts []string, validFrom time.Time, validFor time.Duration, isCA bool) ([]byte, []byte, error) {
privateKey, err := privateKeyBuilder.Build()
if err != nil {
return nil, nil, fmt.Errorf("unable to build private key: %w", err)
}
notBefore := validFrom
notAfter := validFrom.Add(validFor)
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return nil, nil, fmt.Errorf("failed to generate serial number: %v", err)
}
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{"Acme Co"},
},
NotBefore: notBefore,
NotAfter: notAfter,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
BasicConstraintsValid: true,
}
for _, h := range hosts {
if ip := net.ParseIP(h); ip != nil {
template.IPAddresses = append(template.IPAddresses, ip)
} else {
template.DNSNames = append(template.DNSNames, h)
}
}
if isCA {
template.IsCA = true
template.KeyUsage |= x509.KeyUsageCertSign
}
certDERBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(privateKey), privateKey)
if err != nil {
return nil, nil, fmt.Errorf("failed to create certificate: %v", err)
}
certPEMBytes, err := ConvertDERToPEM(certDERBytes, Certificate)
if err != nil {
return nil, nil, fmt.Errorf("faile to convert certificate in DER format into PEM: %v", err)
}
keyDERBytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
if err != nil {
return nil, nil, fmt.Errorf("failed to marshal private key: %v", err)
}
keyPEMBytes, err := ConvertDERToPEM(keyDERBytes, PrivateKey)
if err != nil {
return nil, nil, fmt.Errorf("faile to convert certificate in DER format into PEM: %v", err)
}
return certPEMBytes, keyPEMBytes, nil
}
// ConvertDERToPEM convert certificate in DER format into PEM format.
func ConvertDERToPEM(der []byte, blockType PEMBlockType) ([]byte, error) {
var buf bytes.Buffer
var blockTypeStr string
switch blockType {
case Certificate:
blockTypeStr = "CERTIFICATE"
case PrivateKey:
blockTypeStr = "PRIVATE KEY"
default:
return nil, fmt.Errorf("unknown PEM block type %d", blockType)
}
if err := pem.Encode(&buf, &pem.Block{Type: blockTypeStr, Bytes: der}); err != nil {
return nil, fmt.Errorf("failed to encode DER data into PEM: %v", err)
}
return buf.Bytes(), nil
}
func publicKey(privateKey interface{}) interface{} {
switch k := privateKey.(type) {
case *rsa.PrivateKey:
return &k.PublicKey
case *ecdsa.PrivateKey:
return &k.PublicKey
case ed25519.PrivateKey:
return k.Public().(ed25519.PublicKey)
default:
return nil
}
}
// PrivateKeyBuilder interface for a private key builder.
type PrivateKeyBuilder interface {
Build() (interface{}, error)
}
// RSAKeyBuilder builder of RSA private key.
type RSAKeyBuilder struct {
keySizeInBits int
}
// WithKeySize configure the key size to use with RSA.
func (rkb RSAKeyBuilder) WithKeySize(bits int) RSAKeyBuilder {
rkb.keySizeInBits = bits
return rkb
}
// Build a RSA private key.
func (rkb RSAKeyBuilder) Build() (interface{}, error) {
return rsa.GenerateKey(rand.Reader, rkb.keySizeInBits)
}
// Ed25519KeyBuilder builder of Ed25519 private key.
type Ed25519KeyBuilder struct{}
// Build an Ed25519 private key.
func (ekb Ed25519KeyBuilder) Build() (interface{}, error) {
_, priv, err := ed25519.GenerateKey(rand.Reader)
return priv, err
}
// ECDSAKeyBuilder builder of ECDSA private key.
type ECDSAKeyBuilder struct {
curve elliptic.Curve
}
// WithCurve configure the curve to use for the ECDSA private key.
func (ekb ECDSAKeyBuilder) WithCurve(curve elliptic.Curve) ECDSAKeyBuilder {
ekb.curve = curve
return ekb
}
// Build an ECDSA private key.
func (ekb ECDSAKeyBuilder) Build() (interface{}, error) {
return ecdsa.GenerateKey(ekb.curve, rand.Reader)
}

View File

@ -1,169 +0,0 @@
package utils
import (
"crypto/elliptic"
"crypto/tls"
"runtime"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/authelia/authelia/v4/internal/configuration/schema"
)
func TestShouldSetupDefaultTLSMinVersionOnErr(t *testing.T) {
schemaTLSConfig := &schema.TLSConfig{
MinimumVersion: "NotAVersion",
ServerName: "golang.org",
SkipVerify: true,
}
tlsConfig := NewTLSConfig(schemaTLSConfig, tls.VersionTLS12, nil)
assert.Equal(t, uint16(tls.VersionTLS12), tlsConfig.MinVersion)
assert.Equal(t, "golang.org", tlsConfig.ServerName)
assert.True(t, tlsConfig.InsecureSkipVerify)
}
func TestShouldReturnCorrectTLSVersions(t *testing.T) {
tls13 := uint16(tls.VersionTLS13)
tls12 := uint16(tls.VersionTLS12)
tls11 := uint16(tls.VersionTLS11)
tls10 := uint16(tls.VersionTLS10)
version, err := TLSStringToTLSConfigVersion(TLS13)
assert.Equal(t, tls13, version)
assert.NoError(t, err)
version, err = TLSStringToTLSConfigVersion("TLS" + TLS13)
assert.Equal(t, tls13, version)
assert.NoError(t, err)
version, err = TLSStringToTLSConfigVersion(TLS12)
assert.Equal(t, tls12, version)
assert.NoError(t, err)
version, err = TLSStringToTLSConfigVersion("TLS" + TLS12)
assert.Equal(t, tls12, version)
assert.NoError(t, err)
version, err = TLSStringToTLSConfigVersion(TLS11)
assert.Equal(t, tls11, version)
assert.NoError(t, err)
version, err = TLSStringToTLSConfigVersion("TLS" + TLS11)
assert.Equal(t, tls11, version)
assert.NoError(t, err)
version, err = TLSStringToTLSConfigVersion(TLS10)
assert.Equal(t, tls10, version)
assert.NoError(t, err)
version, err = TLSStringToTLSConfigVersion("TLS" + TLS10)
assert.Equal(t, tls10, version)
assert.NoError(t, err)
}
func TestShouldReturnZeroAndErrorOnInvalidTLSVersions(t *testing.T) {
version, err := TLSStringToTLSConfigVersion("TLS1.4")
assert.Error(t, err)
assert.Equal(t, uint16(0), version)
assert.EqualError(t, err, "supplied tls version isn't supported")
version, err = TLSStringToTLSConfigVersion("SSL3.0")
assert.Error(t, err)
assert.Equal(t, uint16(0), version)
assert.EqualError(t, err, "supplied tls version isn't supported")
}
func TestShouldReturnErrWhenX509DirectoryNotExist(t *testing.T) {
pool, warnings, errors := NewX509CertPool("/tmp/asdfzyxabc123/not/a/real/dir")
assert.NotNil(t, pool)
if runtime.GOOS == windows {
require.Len(t, warnings, 1)
assert.EqualError(t, warnings[0], "could not load system certificate pool which may result in untrusted certificate issues: crypto/x509: system root pool is not available on Windows")
} else {
assert.Len(t, warnings, 0)
}
require.Len(t, errors, 1)
if runtime.GOOS == windows {
assert.EqualError(t, errors[0], "could not read certificates from directory open /tmp/asdfzyxabc123/not/a/real/dir: The system cannot find the path specified.")
} else {
assert.EqualError(t, errors[0], "could not read certificates from directory open /tmp/asdfzyxabc123/not/a/real/dir: no such file or directory")
}
}
func TestShouldNotReturnErrWhenX509DirectoryExist(t *testing.T) {
pool, warnings, errors := NewX509CertPool("/tmp")
assert.NotNil(t, pool)
if runtime.GOOS == windows {
require.Len(t, warnings, 1)
assert.EqualError(t, warnings[0], "could not load system certificate pool which may result in untrusted certificate issues: crypto/x509: system root pool is not available on Windows")
} else {
assert.Len(t, warnings, 0)
}
assert.Len(t, errors, 0)
}
func TestShouldReadCertsFromDirectoryButNotKeys(t *testing.T) {
pool, warnings, errors := NewX509CertPool("../suites/common/ssl/")
assert.NotNil(t, pool)
require.Len(t, errors, 1)
if runtime.GOOS == "windows" {
require.Len(t, warnings, 1)
assert.EqualError(t, warnings[0], "could not load system certificate pool which may result in untrusted certificate issues: crypto/x509: system root pool is not available on Windows")
} else {
assert.Len(t, warnings, 0)
}
assert.EqualError(t, errors[0], "could not import certificate key.pem")
}
func TestShouldGenerateCertificateAndPersistIt(t *testing.T) {
testCases := []struct {
Name string
PrivateKeyBuilder PrivateKeyBuilder
}{
{
Name: "P224",
PrivateKeyBuilder: ECDSAKeyBuilder{}.WithCurve(elliptic.P224()),
},
{
Name: "P256",
PrivateKeyBuilder: ECDSAKeyBuilder{}.WithCurve(elliptic.P256()),
},
{
Name: "P384",
PrivateKeyBuilder: ECDSAKeyBuilder{}.WithCurve(elliptic.P384()),
},
{
Name: "P521",
PrivateKeyBuilder: ECDSAKeyBuilder{}.WithCurve(elliptic.P521()),
},
{
Name: "Ed25519",
PrivateKeyBuilder: Ed25519KeyBuilder{},
},
{
Name: "RSA",
PrivateKeyBuilder: RSAKeyBuilder{keySizeInBits: 2048},
},
}
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
certBytes, keyBytes, err := GenerateCertificate(tc.PrivateKeyBuilder, []string{"authelia.com", "example.org"}, time.Now(), 3*time.Hour, false)
require.NoError(t, err)
assert.True(t, len(certBytes) > 0)
assert.True(t, len(keyBytes) > 0)
})
}
}

View File

@ -31,6 +31,36 @@ const (
unknown = "unknown"
)
// X.509 consts.
const (
BlockTypeRSAPrivateKey = "RSA PRIVATE KEY"
BlockTypeRSAPublicKey = "RSA PUBLIC KEY"
BlockTypeECDSAPrivateKey = "EC PRIVATE KEY"
BlockTypePKCS8PrivateKey = "PRIVATE KEY"
BlockTypePKIXPublicKey = "PUBLIC KEY"
BlockTypeCertificate = "CERTIFICATE"
BlockTypeCertificateRequest = "CERTIFICATE REQUEST"
KeyAlgorithmRSA = "RSA"
KeyAlgorithmECDSA = "ECDSA"
KeyAlgorithmEd25519 = "ED25519"
HashAlgorithmSHA1 = "SHA1"
HashAlgorithmSHA256 = "SHA256"
HashAlgorithmSHA384 = "SHA384"
HashAlgorithmSHA512 = "SHA512"
EllipticCurveP224 = "P224"
EllipticCurveP256 = "P256"
EllipticCurveP384 = "P384"
EllipticCurveP521 = "P521"
EllipticCurveAltP224 = "P-224"
EllipticCurveAltP256 = "P-256"
EllipticCurveAltP384 = "P-384"
EllipticCurveAltP521 = "P-521"
)
const (
// Hour is an int based representation of the time unit.
Hour = time.Minute * 60 //nolint:revive

View File

@ -0,0 +1,582 @@
package utils
import (
"bytes"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"errors"
"fmt"
"math/big"
"net"
"os"
"path/filepath"
"strings"
"time"
"github.com/authelia/authelia/v4/internal/configuration/schema"
"github.com/authelia/authelia/v4/internal/logging"
)
// PEMBlockType represent an enum of the existing PEM block types.
type PEMBlockType int
const (
// Certificate block type.
Certificate PEMBlockType = iota
// PrivateKey block type.
PrivateKey
)
// GenerateCertificate generate a certificate given a private key. RSA, Ed25519 and ECDSA are officially supported.
func GenerateCertificate(privateKeyBuilder PrivateKeyBuilder, hosts []string, validFrom time.Time, validFor time.Duration, isCA bool) ([]byte, []byte, error) {
privateKey, err := privateKeyBuilder.Build()
if err != nil {
return nil, nil, fmt.Errorf("unable to build private key: %w", err)
}
notBefore := validFrom
notAfter := validFrom.Add(validFor)
serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
if err != nil {
return nil, nil, fmt.Errorf("failed to generate serial number: %v", err)
}
template := x509.Certificate{
SerialNumber: serialNumber,
Subject: pkix.Name{
Organization: []string{"Acme Co"},
},
NotBefore: notBefore,
NotAfter: notAfter,
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
BasicConstraintsValid: true,
}
for _, h := range hosts {
if ip := net.ParseIP(h); ip != nil {
template.IPAddresses = append(template.IPAddresses, ip)
} else {
template.DNSNames = append(template.DNSNames, h)
}
}
if isCA {
template.IsCA = true
template.KeyUsage |= x509.KeyUsageCertSign
}
certDERBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(privateKey), privateKey)
if err != nil {
return nil, nil, fmt.Errorf("failed to create certificate: %v", err)
}
certPEMBytes, err := ConvertDERToPEM(certDERBytes, Certificate)
if err != nil {
return nil, nil, fmt.Errorf("failed to convert certificate in DER format into PEM: %v", err)
}
keyDERBytes, err := x509.MarshalPKCS8PrivateKey(privateKey)
if err != nil {
return nil, nil, fmt.Errorf("failed to marshal private key: %v", err)
}
keyPEMBytes, err := ConvertDERToPEM(keyDERBytes, PrivateKey)
if err != nil {
return nil, nil, fmt.Errorf("faile to convert certificate in DER format into PEM: %v", err)
}
return certPEMBytes, keyPEMBytes, nil
}
// ConvertDERToPEM convert certificate in DER format into PEM format.
func ConvertDERToPEM(der []byte, blockType PEMBlockType) ([]byte, error) {
var buf bytes.Buffer
var blockTypeStr string
switch blockType {
case Certificate:
blockTypeStr = "CERTIFICATE"
case PrivateKey:
blockTypeStr = "PRIVATE KEY"
default:
return nil, fmt.Errorf("unknown PEM block type %d", blockType)
}
if err := pem.Encode(&buf, &pem.Block{Type: blockTypeStr, Bytes: der}); err != nil {
return nil, fmt.Errorf("failed to encode DER data into PEM: %v", err)
}
return buf.Bytes(), nil
}
func publicKey(privateKey interface{}) interface{} {
switch k := privateKey.(type) {
case *rsa.PrivateKey:
return &k.PublicKey
case *ecdsa.PrivateKey:
return &k.PublicKey
case ed25519.PrivateKey:
return k.Public().(ed25519.PublicKey)
default:
return nil
}
}
// PrivateKeyBuilder interface for a private key builder.
type PrivateKeyBuilder interface {
Build() (interface{}, error)
}
// RSAKeyBuilder builder of RSA private key.
type RSAKeyBuilder struct {
keySizeInBits int
}
// WithKeySize configure the key size to use with RSA.
func (rkb RSAKeyBuilder) WithKeySize(bits int) RSAKeyBuilder {
rkb.keySizeInBits = bits
return rkb
}
// Build a RSA private key.
func (rkb RSAKeyBuilder) Build() (interface{}, error) {
return rsa.GenerateKey(rand.Reader, rkb.keySizeInBits)
}
// Ed25519KeyBuilder builder of Ed25519 private key.
type Ed25519KeyBuilder struct{}
// Build an Ed25519 private key.
func (ekb Ed25519KeyBuilder) Build() (interface{}, error) {
_, priv, err := ed25519.GenerateKey(rand.Reader)
return priv, err
}
// ECDSAKeyBuilder builder of ECDSA private key.
type ECDSAKeyBuilder struct {
curve elliptic.Curve
}
// WithCurve configure the curve to use for the ECDSA private key.
func (ekb ECDSAKeyBuilder) WithCurve(curve elliptic.Curve) ECDSAKeyBuilder {
ekb.curve = curve
return ekb
}
// Build an ECDSA private key.
func (ekb ECDSAKeyBuilder) Build() (interface{}, error) {
return ecdsa.GenerateKey(ekb.curve, rand.Reader)
}
// ParseX509FromPEM parses PEM bytes and returns a PKCS key.
func ParseX509FromPEM(data []byte) (key interface{}, err error) {
block, _ := pem.Decode(data)
if block == nil {
return nil, errors.New("failed to parse PEM block containing the key")
}
switch block.Type {
case BlockTypeRSAPrivateKey:
key, err = x509.ParsePKCS1PrivateKey(block.Bytes)
case BlockTypeECDSAPrivateKey:
key, err = x509.ParseECPrivateKey(block.Bytes)
case BlockTypePKCS8PrivateKey:
key, err = x509.ParsePKCS8PrivateKey(block.Bytes)
case BlockTypeRSAPublicKey:
key, err = x509.ParsePKCS1PublicKey(block.Bytes)
case BlockTypePKIXPublicKey:
key, err = x509.ParsePKIXPublicKey(block.Bytes)
case BlockTypeCertificate:
key, err = x509.ParseCertificate(block.Bytes)
default:
return nil, fmt.Errorf("unknown block type: %s", block.Type)
}
if err != nil {
return nil, err
}
return key, nil
}
// CastX509AsCertificate converts an interface to an *x509.Certificate.
func CastX509AsCertificate(c interface{}) (certificate *x509.Certificate, ok bool) {
switch t := c.(type) {
case x509.Certificate:
return &t, true
case *x509.Certificate:
return t, true
default:
return nil, false
}
}
// IsX509PrivateKey returns true if the provided interface is an rsa.PrivateKey, ecdsa.PrivateKey, or ed25519.PrivateKey.
func IsX509PrivateKey(i interface{}) bool {
switch i.(type) {
case rsa.PrivateKey, *rsa.PrivateKey, ecdsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey, *ed25519.PrivateKey:
return true
default:
return false
}
}
// NewTLSConfig generates a tls.Config from a schema.TLSConfig and a x509.CertPool.
func NewTLSConfig(config *schema.TLSConfig, defaultMinVersion uint16, certPool *x509.CertPool) (tlsConfig *tls.Config) {
minVersion, err := TLSStringToTLSConfigVersion(config.MinimumVersion)
if err != nil {
minVersion = defaultMinVersion
}
return &tls.Config{
ServerName: config.ServerName,
InsecureSkipVerify: config.SkipVerify, //nolint:gosec // Informed choice by user. Off by default.
MinVersion: minVersion,
RootCAs: certPool,
}
}
// NewX509CertPool generates a x509.CertPool from the system PKI and the directory specified.
func NewX509CertPool(directory string) (certPool *x509.CertPool, warnings []error, errors []error) {
certPool, err := x509.SystemCertPool()
if err != nil {
warnings = append(warnings, fmt.Errorf("could not load system certificate pool which may result in untrusted certificate issues: %v", err))
certPool = x509.NewCertPool()
}
logger := logging.Logger()
logger.Tracef("Starting scan of directory %s for certificates", directory)
if directory != "" {
certsFileInfo, err := os.ReadDir(directory)
if err != nil {
errors = append(errors, fmt.Errorf("could not read certificates from directory %v", err))
} else {
for _, certFileInfo := range certsFileInfo {
nameLower := strings.ToLower(certFileInfo.Name())
if !certFileInfo.IsDir() && (strings.HasSuffix(nameLower, ".cer") || strings.HasSuffix(nameLower, ".crt") || strings.HasSuffix(nameLower, ".pem")) {
certPath := filepath.Join(directory, certFileInfo.Name())
logger.Tracef("Found possible cert %s, attempting to add it to the pool", certPath)
certBytes, err := os.ReadFile(certPath)
if err != nil {
errors = append(errors, fmt.Errorf("could not read certificate %v", err))
} else if ok := certPool.AppendCertsFromPEM(certBytes); !ok {
errors = append(errors, fmt.Errorf("could not import certificate %s", certFileInfo.Name()))
}
}
}
}
}
logger.Tracef("Finished scan of directory %s for certificates", directory)
return certPool, warnings, errors
}
// TLSStringToTLSConfigVersion returns a go crypto/tls version for a tls.Config based on string input.
func TLSStringToTLSConfigVersion(input string) (version uint16, err error) {
switch strings.ToUpper(input) {
case "TLS1.3", TLS13:
return tls.VersionTLS13, nil
case "TLS1.2", TLS12:
return tls.VersionTLS12, nil
case "TLS1.1", TLS11:
return tls.VersionTLS11, nil
case "TLS1.0", TLS10:
return tls.VersionTLS10, nil
}
return 0, ErrTLSVersionNotSupported
}
// WriteCertificateBytesToPEM writes a certificate/csr to a file in the PEM format.
func WriteCertificateBytesToPEM(cert []byte, path string, csr bool) (err error) {
out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return fmt.Errorf("failed to open %s for writing: %w", path, err)
}
blockType := BlockTypeCertificate
if csr {
blockType = BlockTypeCertificateRequest
}
if err = pem.Encode(out, &pem.Block{Bytes: cert, Type: blockType}); err != nil {
_ = out.Close()
return err
}
return out.Close()
}
// WriteKeyToPEM writes a key that can be encoded as a PEM to a file in the PEM format.
func WriteKeyToPEM(key interface{}, path string, pkcs8 bool) (err error) {
pemBlock, err := PEMBlockFromX509Key(key, pkcs8)
if err != nil {
return err
}
out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
if err != nil {
return fmt.Errorf("failed to open %s for writing: %w", path, err)
}
if err = pem.Encode(out, pemBlock); err != nil {
_ = out.Close()
return err
}
return out.Close()
}
// PEMBlockFromX509Key turns a PublicKey or PrivateKey into a pem.Block.
func PEMBlockFromX509Key(key interface{}, pkcs8 bool) (pemBlock *pem.Block, err error) {
var (
data []byte
blockType string
)
switch k := key.(type) {
case *rsa.PrivateKey:
if pkcs8 {
blockType = BlockTypePKCS8PrivateKey
data, err = x509.MarshalPKCS8PrivateKey(key)
break
}
blockType = BlockTypeRSAPrivateKey
data = x509.MarshalPKCS1PrivateKey(k)
case *ecdsa.PrivateKey:
if pkcs8 {
blockType = BlockTypePKCS8PrivateKey
data, err = x509.MarshalPKCS8PrivateKey(key)
break
}
blockType = BlockTypeECDSAPrivateKey
data, err = x509.MarshalECPrivateKey(k)
case ed25519.PrivateKey:
blockType = BlockTypePKCS8PrivateKey
data, err = x509.MarshalPKCS8PrivateKey(k)
case *rsa.PublicKey:
if pkcs8 {
blockType = BlockTypePKIXPublicKey
data, err = x509.MarshalPKIXPublicKey(key)
break
}
blockType = BlockTypeRSAPublicKey
data = x509.MarshalPKCS1PublicKey(k)
case *ecdsa.PublicKey, ed25519.PublicKey:
blockType = BlockTypePKIXPublicKey
data, err = x509.MarshalPKIXPublicKey(k)
default:
err = fmt.Errorf("failed to match key type: %T", k)
}
if err != nil {
return nil, fmt.Errorf("failed to marshal key: %w", err)
}
return &pem.Block{
Type: blockType,
Bytes: data,
}, nil
}
// KeySigAlgorithmFromString returns a x509.PublicKeyAlgorithm and x509.SignatureAlgorithm given a keyAlgorithm and signatureAlgorithm string.
func KeySigAlgorithmFromString(keyAlgorithm, signatureAlgorithm string) (keyAlg x509.PublicKeyAlgorithm, sigAlg x509.SignatureAlgorithm) {
keyAlg = PublicKeyAlgorithmFromString(keyAlgorithm)
if keyAlg == x509.UnknownPublicKeyAlgorithm {
return x509.UnknownPublicKeyAlgorithm, x509.UnknownSignatureAlgorithm
}
switch keyAlg {
case x509.RSA:
return keyAlg, RSASignatureAlgorithmFromString(signatureAlgorithm)
case x509.ECDSA:
return keyAlg, ECDSASignatureAlgorithmFromString(signatureAlgorithm)
case x509.Ed25519:
return keyAlg, x509.PureEd25519
default:
return keyAlg, x509.UnknownSignatureAlgorithm
}
}
// PublicKeyAlgorithmFromString returns a x509.PublicKeyAlgorithm given an appropriate string.
func PublicKeyAlgorithmFromString(algorithm string) (alg x509.PublicKeyAlgorithm) {
switch strings.ToUpper(algorithm) {
case KeyAlgorithmRSA:
return x509.RSA
case KeyAlgorithmECDSA:
return x509.ECDSA
case KeyAlgorithmEd25519:
return x509.Ed25519
default:
return x509.UnknownPublicKeyAlgorithm
}
}
// RSASignatureAlgorithmFromString returns a x509.SignatureAlgorithm for the RSA x509.PublicKeyAlgorithm given an
// algorithm string.
func RSASignatureAlgorithmFromString(algorithm string) (alg x509.SignatureAlgorithm) {
switch strings.ToUpper(algorithm) {
case HashAlgorithmSHA1:
return x509.SHA1WithRSA
case HashAlgorithmSHA256:
return x509.SHA256WithRSA
case HashAlgorithmSHA384:
return x509.SHA384WithRSA
case HashAlgorithmSHA512:
return x509.SHA512WithRSA
default:
return x509.UnknownSignatureAlgorithm
}
}
// ECDSASignatureAlgorithmFromString returns a x509.SignatureAlgorithm for the ECDSA x509.PublicKeyAlgorithm given an
// algorithm string.
func ECDSASignatureAlgorithmFromString(algorithm string) (alg x509.SignatureAlgorithm) {
switch strings.ToUpper(algorithm) {
case HashAlgorithmSHA1:
return x509.ECDSAWithSHA1
case HashAlgorithmSHA256:
return x509.ECDSAWithSHA256
case HashAlgorithmSHA384:
return x509.ECDSAWithSHA384
case HashAlgorithmSHA512:
return x509.ECDSAWithSHA512
default:
return x509.UnknownSignatureAlgorithm
}
}
// EllipticCurveFromString turns a string into an elliptic.Curve.
func EllipticCurveFromString(curveString string) (curve elliptic.Curve) {
switch strings.ToUpper(curveString) {
case EllipticCurveAltP224, EllipticCurveP224:
return elliptic.P224()
case EllipticCurveAltP256, EllipticCurveP256:
return elliptic.P256()
case EllipticCurveAltP384, EllipticCurveP384:
return elliptic.P384()
case EllipticCurveAltP521, EllipticCurveP521:
return elliptic.P521()
default:
return nil
}
}
// PublicKeyFromPrivateKey returns a PublicKey when provided with a PrivateKey.
func PublicKeyFromPrivateKey(privateKey interface{}) (publicKey interface{}) {
switch k := privateKey.(type) {
case *rsa.PrivateKey:
return &k.PublicKey
case *ecdsa.PrivateKey:
return &k.PublicKey
case ed25519.PrivateKey:
return k.Public().(ed25519.PublicKey)
default:
return nil
}
}
// X509ParseKeyUsage parses a list of key usages. If provided with an empty list returns a default of Key Encipherment
// and Digital Signature unless ca is true in which case it returns Cert Sign.
func X509ParseKeyUsage(keyUsages []string, ca bool) (keyUsage x509.KeyUsage) {
if len(keyUsages) == 0 {
keyUsage = x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature
if ca {
keyUsage |= x509.KeyUsageCertSign
}
return keyUsage
}
for _, keyUsageString := range keyUsages {
switch strings.ToLower(keyUsageString) {
case "digitalsignature", "digital_signature":
keyUsage |= x509.KeyUsageDigitalSignature
case "keyencipherment", "key_encipherment":
keyUsage |= x509.KeyUsageKeyEncipherment
case "dataencipherment", "data_encipherment":
keyUsage |= x509.KeyUsageDataEncipherment
case "keyagreement", "key_agreement":
keyUsage |= x509.KeyUsageKeyAgreement
case "certsign", "cert_sign", "certificatesign", "certificate_sign":
keyUsage |= x509.KeyUsageCertSign
case "crlsign", "crl_sign":
keyUsage |= x509.KeyUsageCRLSign
case "encipheronly", "encipher_only":
keyUsage |= x509.KeyUsageEncipherOnly
case "decipheronly", "decipher_only":
keyUsage |= x509.KeyUsageDecipherOnly
}
}
return keyUsage
}
// X509ParseExtendedKeyUsage parses a list of extended key usages. If provided with an empty list returns a default of
// Server Auth unless ca is true in which case it returns a default of Any.
func X509ParseExtendedKeyUsage(extKeyUsages []string, ca bool) (extKeyUsage []x509.ExtKeyUsage) {
if len(extKeyUsages) == 0 {
if ca {
extKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageAny}
} else {
extKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
}
return extKeyUsage
}
loop:
for _, extKeyUsageString := range extKeyUsages {
switch strings.ToLower(extKeyUsageString) {
case "any":
extKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageAny}
break loop
case "serverauth", "server_auth":
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageServerAuth)
case "clientauth", "client_auth":
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageClientAuth)
case "codesigning", "code_signing":
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageCodeSigning)
case "emailprotection", "email_protection":
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageEmailProtection)
case "ipsecendsystem", "ipsec_endsystem", "ipsec_end_system":
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageIPSECEndSystem)
case "ipsectunnel", "ipsec_tunnel":
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageIPSECTunnel)
case "ipsecuser", "ipsec_user":
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageIPSECUser)
case "ocspsigning", "ocsp_signing":
extKeyUsage = append(extKeyUsage, x509.ExtKeyUsageOCSPSigning)
}
}
return extKeyUsage
}

View File

@ -0,0 +1,538 @@
package utils
import (
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rsa"
"crypto/tls"
"crypto/x509"
"runtime"
"strings"
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/authelia/authelia/v4/internal/configuration/schema"
)
func TestShouldSetupDefaultTLSMinVersionOnErr(t *testing.T) {
schemaTLSConfig := &schema.TLSConfig{
MinimumVersion: "NotAVersion",
ServerName: "golang.org",
SkipVerify: true,
}
tlsConfig := NewTLSConfig(schemaTLSConfig, tls.VersionTLS12, nil)
assert.Equal(t, uint16(tls.VersionTLS12), tlsConfig.MinVersion)
assert.Equal(t, "golang.org", tlsConfig.ServerName)
assert.True(t, tlsConfig.InsecureSkipVerify)
}
func TestShouldReturnCorrectTLSVersions(t *testing.T) {
tls13 := uint16(tls.VersionTLS13)
tls12 := uint16(tls.VersionTLS12)
tls11 := uint16(tls.VersionTLS11)
tls10 := uint16(tls.VersionTLS10)
version, err := TLSStringToTLSConfigVersion(TLS13)
assert.Equal(t, tls13, version)
assert.NoError(t, err)
version, err = TLSStringToTLSConfigVersion("TLS" + TLS13)
assert.Equal(t, tls13, version)
assert.NoError(t, err)
version, err = TLSStringToTLSConfigVersion(TLS12)
assert.Equal(t, tls12, version)
assert.NoError(t, err)
version, err = TLSStringToTLSConfigVersion("TLS" + TLS12)
assert.Equal(t, tls12, version)
assert.NoError(t, err)
version, err = TLSStringToTLSConfigVersion(TLS11)
assert.Equal(t, tls11, version)
assert.NoError(t, err)
version, err = TLSStringToTLSConfigVersion("TLS" + TLS11)
assert.Equal(t, tls11, version)
assert.NoError(t, err)
version, err = TLSStringToTLSConfigVersion(TLS10)
assert.Equal(t, tls10, version)
assert.NoError(t, err)
version, err = TLSStringToTLSConfigVersion("TLS" + TLS10)
assert.Equal(t, tls10, version)
assert.NoError(t, err)
}
func TestShouldReturnZeroAndErrorOnInvalidTLSVersions(t *testing.T) {
version, err := TLSStringToTLSConfigVersion("TLS1.4")
assert.Error(t, err)
assert.Equal(t, uint16(0), version)
assert.EqualError(t, err, "supplied tls version isn't supported")
version, err = TLSStringToTLSConfigVersion("SSL3.0")
assert.Error(t, err)
assert.Equal(t, uint16(0), version)
assert.EqualError(t, err, "supplied tls version isn't supported")
}
func TestShouldReturnErrWhenX509DirectoryNotExist(t *testing.T) {
pool, warnings, errors := NewX509CertPool("/tmp/asdfzyxabc123/not/a/real/dir")
assert.NotNil(t, pool)
if runtime.GOOS == windows {
require.Len(t, warnings, 1)
assert.EqualError(t, warnings[0], "could not load system certificate pool which may result in untrusted certificate issues: crypto/x509: system root pool is not available on Windows")
} else {
assert.Len(t, warnings, 0)
}
require.Len(t, errors, 1)
if runtime.GOOS == windows {
assert.EqualError(t, errors[0], "could not read certificates from directory open /tmp/asdfzyxabc123/not/a/real/dir: The system cannot find the path specified.")
} else {
assert.EqualError(t, errors[0], "could not read certificates from directory open /tmp/asdfzyxabc123/not/a/real/dir: no such file or directory")
}
}
func TestShouldNotReturnErrWhenX509DirectoryExist(t *testing.T) {
pool, warnings, errors := NewX509CertPool("/tmp")
assert.NotNil(t, pool)
if runtime.GOOS == windows {
require.Len(t, warnings, 1)
assert.EqualError(t, warnings[0], "could not load system certificate pool which may result in untrusted certificate issues: crypto/x509: system root pool is not available on Windows")
} else {
assert.Len(t, warnings, 0)
}
assert.Len(t, errors, 0)
}
func TestShouldReadCertsFromDirectoryButNotKeys(t *testing.T) {
pool, warnings, errors := NewX509CertPool("../suites/common/ssl/")
assert.NotNil(t, pool)
require.Len(t, errors, 1)
if runtime.GOOS == "windows" {
require.Len(t, warnings, 1)
assert.EqualError(t, warnings[0], "could not load system certificate pool which may result in untrusted certificate issues: crypto/x509: system root pool is not available on Windows")
} else {
assert.Len(t, warnings, 0)
}
assert.EqualError(t, errors[0], "could not import certificate key.pem")
}
func TestShouldGenerateCertificateAndPersistIt(t *testing.T) {
testCases := []struct {
Name string
PrivateKeyBuilder PrivateKeyBuilder
}{
{
Name: "P224",
PrivateKeyBuilder: ECDSAKeyBuilder{}.WithCurve(elliptic.P224()),
},
{
Name: "P256",
PrivateKeyBuilder: ECDSAKeyBuilder{}.WithCurve(elliptic.P256()),
},
{
Name: "P384",
PrivateKeyBuilder: ECDSAKeyBuilder{}.WithCurve(elliptic.P384()),
},
{
Name: "P521",
PrivateKeyBuilder: ECDSAKeyBuilder{}.WithCurve(elliptic.P521()),
},
{
Name: "Ed25519",
PrivateKeyBuilder: Ed25519KeyBuilder{},
},
{
Name: "RSA",
PrivateKeyBuilder: RSAKeyBuilder{keySizeInBits: 2048},
},
}
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
certBytes, keyBytes, err := GenerateCertificate(tc.PrivateKeyBuilder, []string{"authelia.com", "example.org"}, time.Now(), 3*time.Hour, false)
require.NoError(t, err)
assert.True(t, len(certBytes) > 0)
assert.True(t, len(keyBytes) > 0)
})
}
}
func TestShouldParseKeySigAlgorithm(t *testing.T) {
testCases := []struct {
Name string
InputKey, InputSig string
ExpectedKeyAlg x509.PublicKeyAlgorithm
ExpectedSigAlg x509.SignatureAlgorithm
}{
{
Name: "ShouldNotParseInvalidKeyAlg",
InputKey: "DDD",
InputSig: "SHA1",
ExpectedKeyAlg: x509.UnknownPublicKeyAlgorithm,
ExpectedSigAlg: x509.UnknownSignatureAlgorithm,
},
{
Name: "ShouldParseKeyRSASigSHA1",
InputKey: "RSA",
InputSig: "SHA1",
ExpectedKeyAlg: x509.RSA,
ExpectedSigAlg: x509.SHA1WithRSA,
},
{
Name: "ShouldParseKeyRSASigSHA256",
InputKey: "RSA",
InputSig: "SHA256",
ExpectedKeyAlg: x509.RSA,
ExpectedSigAlg: x509.SHA256WithRSA,
},
{
Name: "ShouldParseKeyRSASigSHA384",
InputKey: "RSA",
InputSig: "SHA384",
ExpectedKeyAlg: x509.RSA,
ExpectedSigAlg: x509.SHA384WithRSA,
},
{
Name: "ShouldParseKeyRSASigSHA512",
InputKey: "RSA",
InputSig: "SHA512",
ExpectedKeyAlg: x509.RSA,
ExpectedSigAlg: x509.SHA512WithRSA,
},
{
Name: "ShouldNotParseKeyRSASigInvalid",
InputKey: "RSA",
InputSig: "INVALID",
ExpectedKeyAlg: x509.RSA,
ExpectedSigAlg: x509.UnknownSignatureAlgorithm,
},
{
Name: "ShouldParseKeyECDSASigSHA1",
InputKey: "ECDSA",
InputSig: "SHA1",
ExpectedKeyAlg: x509.ECDSA,
ExpectedSigAlg: x509.ECDSAWithSHA1,
},
{
Name: "ShouldParseKeyECDSASigSHA256",
InputKey: "ECDSA",
InputSig: "SHA256",
ExpectedKeyAlg: x509.ECDSA,
ExpectedSigAlg: x509.ECDSAWithSHA256,
},
{
Name: "ShouldParseKeyECDSASigSHA384",
InputKey: "ECDSA",
InputSig: "SHA384",
ExpectedKeyAlg: x509.ECDSA,
ExpectedSigAlg: x509.ECDSAWithSHA384,
},
{
Name: "ShouldParseKeyECDSASigSHA512",
InputKey: "ECDSA",
InputSig: "SHA512",
ExpectedKeyAlg: x509.ECDSA,
ExpectedSigAlg: x509.ECDSAWithSHA512,
},
{
Name: "ShouldNotParseKeyECDSASigInvalid",
InputKey: "ECDSA",
InputSig: "INVALID",
ExpectedKeyAlg: x509.ECDSA,
ExpectedSigAlg: x509.UnknownSignatureAlgorithm,
},
{
Name: "ShouldParseKeyEd25519SigSHA1",
InputKey: "ED25519",
InputSig: "SHA1",
ExpectedKeyAlg: x509.Ed25519,
ExpectedSigAlg: x509.PureEd25519,
},
{
Name: "ShouldParseKeyEd25519SigSHA256",
InputKey: "ED25519",
InputSig: "SHA256",
ExpectedKeyAlg: x509.Ed25519,
ExpectedSigAlg: x509.PureEd25519,
},
{
Name: "ShouldParseKeyEd25519SigSHA384",
InputKey: "ED25519",
InputSig: "SHA384",
ExpectedKeyAlg: x509.Ed25519,
ExpectedSigAlg: x509.PureEd25519,
},
{
Name: "ShouldParseKeyEd25519SigSHA512",
InputKey: "ED25519",
InputSig: "SHA512",
ExpectedKeyAlg: x509.Ed25519,
ExpectedSigAlg: x509.PureEd25519,
},
{
Name: "ShouldParseKeyEd25519SigInvalid",
InputKey: "ED25519",
InputSig: "INVALID",
ExpectedKeyAlg: x509.Ed25519,
ExpectedSigAlg: x509.PureEd25519,
},
}
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
actualKey, actualSig := KeySigAlgorithmFromString(tc.InputKey, tc.InputSig)
actualKeyLower, actualSigLower := KeySigAlgorithmFromString(strings.ToLower(tc.InputKey), strings.ToLower(tc.InputSig))
assert.Equal(t, tc.ExpectedKeyAlg, actualKey)
assert.Equal(t, tc.ExpectedSigAlg, actualSig)
assert.Equal(t, tc.ExpectedKeyAlg, actualKeyLower)
assert.Equal(t, tc.ExpectedSigAlg, actualSigLower)
})
}
}
func TestShouldParseCurves(t *testing.T) {
testCases := []struct {
Name string
Input string
Expected elliptic.Curve
}{
{
Name: "P224-Standard",
Input: "P224",
Expected: elliptic.P224(),
},
{
Name: "P224-Lowercase",
Input: "p224",
Expected: elliptic.P224(),
},
{
Name: "P224-Hyphenated",
Input: "P-224",
Expected: elliptic.P224(),
},
{
Name: "P256-Standard",
Input: "P256",
Expected: elliptic.P256(),
},
{
Name: "P256-Lowercase",
Input: "p256",
Expected: elliptic.P256(),
},
{
Name: "P256-Hyphenated",
Input: "P-256",
Expected: elliptic.P256(),
},
{
Name: "P384-Standard",
Input: "P384",
Expected: elliptic.P384(),
},
{
Name: "P384-Lowercase",
Input: "p384",
Expected: elliptic.P384(),
},
{
Name: "P384-Hyphenated",
Input: "P-384",
Expected: elliptic.P384(),
},
{
Name: "P521-Standard",
Input: "P521",
Expected: elliptic.P521(),
},
{
Name: "P521-Lowercase",
Input: "p521",
Expected: elliptic.P521(),
},
{
Name: "P521-Hyphenated",
Input: "P-521",
Expected: elliptic.P521(),
},
{
Name: "Invalid",
Input: "521",
Expected: nil,
},
}
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
actual := EllipticCurveFromString(tc.Input)
assert.Equal(t, tc.Expected, actual)
})
}
}
func testMustBuildPrivateKey(b PrivateKeyBuilder) interface{} {
k, err := b.Build()
if err != nil {
panic(err)
}
return k
}
func TestPublicKeyFromPrivateKey(t *testing.T) {
testCases := []struct {
Name string
PrivateKey interface{}
Expected interface{}
}{
{
Name: "RSA2048",
PrivateKey: testMustBuildPrivateKey(RSAKeyBuilder{}.WithKeySize(512)),
Expected: &rsa.PublicKey{},
},
{
Name: "ECDSA-P256",
PrivateKey: testMustBuildPrivateKey(ECDSAKeyBuilder{}.WithCurve(elliptic.P256())),
Expected: &ecdsa.PublicKey{},
},
{
Name: "Ed25519",
PrivateKey: testMustBuildPrivateKey(Ed25519KeyBuilder{}),
Expected: ed25519.PublicKey{},
},
{
Name: "Invalid",
PrivateKey: 8,
Expected: nil,
},
}
for _, tc := range testCases {
t.Run(tc.Name, func(t *testing.T) {
actual := PublicKeyFromPrivateKey(tc.PrivateKey)
if tc.Expected == nil {
assert.Nil(t, actual)
} else {
assert.IsType(t, tc.Expected, actual)
}
})
}
}
func TestX509ParseKeyUsage(t *testing.T) {
testCases := []struct {
name string
have [][]string
ca bool
expected x509.KeyUsage
}{
{
"ShouldParseDefault", nil, false, x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
},
{
"ShouldParseDefaultCA", nil, true, x509.KeyUsageCertSign | x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
},
{
"ShouldParseDigitalSignature", [][]string{{"digital_signature"}, {"Digital_Signature"}, {"digitalsignature"}, {"digitalSignature"}}, false, x509.KeyUsageDigitalSignature,
},
{
"ShouldParseKeyEncipherment", [][]string{{"key_encipherment"}, {"Key_Encipherment"}, {"keyencipherment"}, {"keyEncipherment"}}, false, x509.KeyUsageKeyEncipherment,
},
{
"ShouldParseDataEncipherment", [][]string{{"data_encipherment"}, {"Data_Encipherment"}, {"dataencipherment"}, {"dataEncipherment"}}, false, x509.KeyUsageDataEncipherment,
},
{
"ShouldParseKeyAgreement", [][]string{{"key_agreement"}, {"Key_Agreement"}, {"keyagreement"}, {"keyAgreement"}}, false, x509.KeyUsageKeyAgreement,
},
{
"ShouldParseCertSign", [][]string{{"cert_sign"}, {"Cert_Sign"}, {"certsign"}, {"certSign"}, {"certificate_sign"}, {"Certificate_Sign"}, {"certificatesign"}, {"certificateSign"}}, false, x509.KeyUsageCertSign,
},
{
"ShouldParseCRLSign", [][]string{{"crl_sign"}, {"CRL_Sign"}, {"crlsign"}, {"CRLSign"}}, false, x509.KeyUsageCRLSign,
},
{
"ShouldParseEncipherOnly", [][]string{{"encipher_only"}, {"Encipher_Only"}, {"encipheronly"}, {"encipherOnly"}}, false, x509.KeyUsageEncipherOnly,
},
{
"ShouldParseDecipherOnly", [][]string{{"decipher_only"}, {"Decipher_Only"}, {"decipheronly"}, {"decipherOnly"}}, false, x509.KeyUsageDecipherOnly,
},
{
"ShouldParseMulti", [][]string{{"digitalSignature", "keyEncipherment", "dataEncipherment", "certSign", "crlSign"}}, false, x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment | x509.KeyUsageDataEncipherment | x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if len(tc.have) == 0 {
actual := X509ParseKeyUsage(nil, tc.ca)
assert.Equal(t, tc.expected, actual)
}
for _, have := range tc.have {
t.Run(strings.Join(have, ","), func(t *testing.T) {
actual := X509ParseKeyUsage(have, tc.ca)
assert.Equal(t, tc.expected, actual)
})
}
})
}
}
func TestX509ParseExtendedKeyUsage(t *testing.T) {
testCases := []struct {
name string
have [][]string
ca bool
expected []x509.ExtKeyUsage
}{
{"ShouldParseDefault", nil, false, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}},
{"ShouldParseDefaultCA", nil, true, []x509.ExtKeyUsage{x509.ExtKeyUsageAny}},
{"ShouldParseAny", [][]string{{"any"}, {"Any"}, {"any", "server_auth"}}, false, []x509.ExtKeyUsage{x509.ExtKeyUsageAny}},
{"ShouldParseServerAuth", [][]string{{"server_auth"}, {"Server_Auth"}, {"serverauth"}, {"serverAuth"}}, false, []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}},
{"ShouldParseClientAuth", [][]string{{"client_auth"}, {"Client_Auth"}, {"clientauth"}, {"clientAuth"}}, false, []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}},
{"ShouldParseCodeSigning", [][]string{{"code_signing"}, {"Code_Signing"}, {"codesigning"}, {"codeSigning"}}, false, []x509.ExtKeyUsage{x509.ExtKeyUsageCodeSigning}},
{"ShouldParseEmailProtection", [][]string{{"email_protection"}, {"Email_Protection"}, {"emailprotection"}, {"emailProtection"}}, false, []x509.ExtKeyUsage{x509.ExtKeyUsageEmailProtection}},
{"ShouldParseIPSECEndSystem", [][]string{{"ipsec_endsystem"}, {"IPSEC_Endsystem"}, {"ipsec_end_system"}, {"IPSEC_End_System"}, {"ipsecendsystem"}, {"ipsecEndSystem"}}, false, []x509.ExtKeyUsage{x509.ExtKeyUsageIPSECEndSystem}},
{"ShouldParseIPSECTunnel", [][]string{{"ipsec_tunnel"}, {"IPSEC_Tunnel"}, {"ipsectunnel"}, {"ipsecTunnel"}}, false, []x509.ExtKeyUsage{x509.ExtKeyUsageIPSECTunnel}},
{"ShouldParseIPSECUser", [][]string{{"ipsec_user"}, {"IPSEC_User"}, {"ipsecuser"}, {"ipsecUser"}}, false, []x509.ExtKeyUsage{x509.ExtKeyUsageIPSECUser}},
{"ShouldParseOCSPSigning", [][]string{{"ocsp_signing"}, {"OCSP_Signing"}, {"ocspsigning"}, {"ocspSigning"}}, false, []x509.ExtKeyUsage{x509.ExtKeyUsageOCSPSigning}},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if len(tc.have) == 0 {
actual := X509ParseExtendedKeyUsage(nil, tc.ca)
assert.Equal(t, tc.expected, actual)
}
for _, have := range tc.have {
t.Run(strings.Join(have, ","), func(t *testing.T) {
actual := X509ParseExtendedKeyUsage(have, tc.ca)
assert.Equal(t, tc.expected, actual)
})
}
})
}
}

View File

@ -1,83 +0,0 @@
package utils
import (
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/pem"
"errors"
)
// GenerateRsaKeyPair generate an RSA key pair.
// bits can be 2048 or 4096.
func GenerateRsaKeyPair(bits int) (*rsa.PrivateKey, *rsa.PublicKey) {
privkey, _ := rsa.GenerateKey(rand.Reader, bits)
return privkey, &privkey.PublicKey
}
// ExportRsaPrivateKeyAsPemStr marshal a rsa private key into PEM string.
func ExportRsaPrivateKeyAsPemStr(privkey *rsa.PrivateKey) string {
privkeyBytes := x509.MarshalPKCS1PrivateKey(privkey)
privkeyPem := pem.EncodeToMemory(
&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: privkeyBytes,
},
)
return string(privkeyPem)
}
// ParseRsaPrivateKeyFromPemStr parse a RSA private key from PEM string.
func ParseRsaPrivateKeyFromPemStr(privPEM string) (*rsa.PrivateKey, error) {
block, _ := pem.Decode([]byte(privPEM))
if block == nil {
return nil, errors.New("failed to parse PEM block containing the key")
}
priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
if err != nil {
return nil, err
}
return priv, nil
}
// ExportRsaPublicKeyAsPemStr marshal a RSA public into a PEM string.
func ExportRsaPublicKeyAsPemStr(pubkey *rsa.PublicKey) (string, error) {
pubkeyBytes, err := x509.MarshalPKIXPublicKey(pubkey)
if err != nil {
return "", err
}
pubkeyPem := pem.EncodeToMemory(
&pem.Block{
Type: "RSA PUBLIC KEY",
Bytes: pubkeyBytes,
},
)
return string(pubkeyPem), nil
}
// ParseRsaPublicKeyFromPemStr parse RSA public key from a PEM string.
func ParseRsaPublicKeyFromPemStr(pubPEM string) (*rsa.PublicKey, error) {
block, _ := pem.Decode([]byte(pubPEM))
if block == nil {
return nil, errors.New("failed to parse PEM block containing the key")
}
pub, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
return nil, err
}
switch pub := pub.(type) {
case *rsa.PublicKey:
return pub, nil
default:
break // fall through.
}
return nil, errors.New("key type is not RSA")
}