Skip to content

Commit

Permalink
refactors cert verification, adds --verification-url
Browse files Browse the repository at this point in the history
  • Loading branch information
tisba committed Mar 21, 2022
1 parent 1f9f1d9 commit 51ff3c1
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 42 deletions.
28 changes: 9 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ This is a little pet project to install TLS certificates into your [FRITZ!Box](h

Although it should work with other versions as well, it is only tested with:

* FRITZ!Box Fon WLAN 7530 (FRITZ!OS: 07.28)
* FRITZ!Box 7490 (FRITZ!OS: 07.28)
* FRITZ!Box Fon WLAN 7530 (FRITZ!OS: 07.29)
* FRITZ!Box 7490 (FRITZ!OS: 07.29)

In case you want to know how to do that manually, take a look at AVM's [knowledge base article](https://en.avm.de/service/fritzbox/fritzbox-7390/knowledge-base/publication/show/1525_Importing-your-own-certificate-to-the-FRITZ-Box/).

Expand Down Expand Up @@ -39,17 +39,19 @@ Done :)
General options for `fritz-tls` are:

* `--help` to get usage information
* `--host` (default: `http://fritz.box`) to specify how to talk to your FRITZ!Box. If you want to login with username and password, specify the user like this: `--host http://tisba@fritz.box`. `--host` may also contain a port, which will be used instead of `--tls-port`, for example: `https://user@fritz.box.8080`.
* `--host` (default: `http://fritz.box`) to specify how to talk to your FRITZ!Box. If you want to login with username and password, specify the user in the URL: `--host http://tisba@fritz.box:8080`.
* `--insecure` (optional) to skip TLS verification when talking to `--host` in case it's HTTPS and you currently have a broken or expired TLS certificate.
* `--tls-port` (default: `443`) TLS port of FRITZ!Box. This is used for certificate validation after installing.
* `--verification-url` (optional) to specify what URL to use to check certificate installation. Defaults to `--host`.

`fritz-tls` can install any TLS certificate or aqcuire one using [Let's Encrypt](https://letsencrypt.org).

### Let's Encrypt Mode

By default, Let's Encrypt is used to acquire a certificate, options are:

* `--domain` the domain you want to have your certificate generated for (if `--host` is not `fritz.box`, `--domain` it will default to the host name in `--host`)
* `--email` (optional) your mail address you want to have registered with [Let’s Encrypt expiration service](https://letsencrypt.org/docs/expiration-emails/)
* `--save` (optional) to save generated private key and acquired certificate
* `--domain` the domain you want to have your certificate generated for (if `--host` is not `fritz.box`, `--domain` it will default to the host name in `--host`).
* `--email` (optional) your mail address you want to have registered with [Let’s Encrypt expiration service](https://letsencrypt.org/docs/expiration-emails/).
* `--save` (optional) to save generated private key and acquired certificate.
* `--dns-provider` (default `manual`) to specify one of [lego's](https://github.com/xenolf/lego/tree/master/providers/dns) supported DNS providers. Note that you might have to set environment variables to configure your provider, e.g. `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_REGION` and `AWS_HOSTED_ZONE_ID`. I use name servers by AWS/Route53 and [inwx](https://github.com/xenolf/lego/blob/master/providers/dns/inwx/inwx.go), so I have to provide `INWX_USERNAME`, `INWX_PASSWORD`. I'm not sure if there is a overview, so for now you have to consult the [source](https://github.com/xenolf/lego/tree/master/providers/dns).
* `--dns-resolver` (optional) to specify the resolver to be used for recursive DNS queries. If not provided, the system default will be used. Supported format is `host:port`.

Expand All @@ -74,18 +76,6 @@ These are some things I'd like to to in the future:
* check validity and expiration datex on existing certificate and don't renew unless some `--force-renew` flag or the remainingx cert validty is less then 30 days (the number of days could also be an option). This would make full-automation a lot easier.
* add validation for private keys and certificate before uploading (avoid trying to upload garbage)
* allow password protected private keys (when not provisioned by LE)
* ~~make `--auto-cert` the default and add something like `--manual-upload` instead. That would require less flags for the typical use case.~~
* ~~if `--tls-port` is not given, we should try to use `--host` before failing~~
* ~~add homebrew as a release target for goreleaser~~
* ~~ask for `--user` if not provided (may be empty then) and/or add `--pw-only` flag~~
* ~~allow other then DNS-01 Let's Encrypt challenges and make [legos](https://github.com/xenolf/lego) DNS providers available to make things even more automated!~~
* ~~add `--insecure` to ignore invalid TLS certificates when talking to FRITZ!Box~~
* ~~read FRITZ!Box administrator password from environment~~
* ~~add ability to use already combined private keys and certificate files~~
* ~~add basic Let's Encrypt support~~
* ~~improve detection if certificate installation was successful; currently I'm looking for a string in the response. But maybe we can just wait a little bit and make a https request and check if the certificate is actually being used.~~
* ~~implement FRITZ!Box authentication for user name and password~~
* ~~set up Travis and use [GoReleaser](https://github.com/goreleaser/goreleaser) to build and publish builds~~

## Make Release

Expand Down
3 changes: 1 addition & 2 deletions internal/fritzbox/certificates.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package fritzbox
import (
"io"
"net/http"
"strconv"
"strings"
)

Expand Down Expand Up @@ -39,7 +38,7 @@ func (fb *FritzBox) UploadCertificate(data io.Reader) (bool, string, error) {
// VerifyCertificate uses Go's http.Get with TLS verification
// to see if a valid certificate is actually installed.
func (fb *FritzBox) VerifyCertificate() (bool, error) {
_, err := http.Get("https://" + fb.Domain + ":" + strconv.Itoa(fb.TLSPort))
_, err := http.Get(fb.VerificationURL.String())

if err != nil {
return false, err
Expand Down
14 changes: 8 additions & 6 deletions internal/fritzbox/types.go
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package fritzbox

import "net/url"

// FritzBox holds general information about the FRITZ!Box to talk to
type FritzBox struct {
Host string
User string
Insecure bool
Domain string
TLSPort int
session SessionInfo
Host string
User string
Insecure bool
Domain string
session SessionInfo
VerificationURL *url.URL
}

// SessionInfo holds information about
Expand Down
36 changes: 21 additions & 15 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"log"
"net/url"
"os"
"strconv"

"github.com/tisba/fritz-tls/internal/fritzbox"
"github.com/tisba/fritz-tls/internal/fritzutils"
Expand All @@ -20,12 +19,12 @@ var (
commit string
)

type configOptions struct { // nolint: maligned
host string
user string
adminPassword string
insecure bool
tlsPort int
type configOptions struct {
host string
user string
adminPassword string
insecure bool
verificationURL *url.URL

fullchain string
privatekey string
Expand All @@ -47,11 +46,11 @@ func main() {
config := setupConfiguration()

fritz := &fritzbox.FritzBox{
Host: config.host,
User: config.user,
Insecure: config.insecure,
Domain: config.domain,
TLSPort: config.tlsPort,
Host: config.host,
User: config.user,
Insecure: config.insecure,
Domain: config.domain,
VerificationURL: config.verificationURL,
}

// Login into FRITZ!box
Expand Down Expand Up @@ -123,6 +122,7 @@ func main() {

func setupConfiguration() (config configOptions) {
var manualCert bool
var verificationHost string

flag.StringVar(&config.host, "host", "http://fritz.box", "FRITZ!Box host")
flag.StringVar(&config.adminPassword, "password", "", "FRITZ!Box admin password")
Expand All @@ -135,9 +135,9 @@ func setupConfiguration() (config configOptions) {
flag.StringVar(&config.dnsProviderName, "dns-provider", "manual", "name of DNS provider to use")
flag.BoolVar(&config.saveCert, "save", false, "Save requested certificate and private key to disk")
flag.StringVar(&config.domain, "domain", "", "Desired FQDN of your FRITZ!Box")
flag.IntVar(&config.tlsPort, "tls-port", 443, "TLS port used by FRITZ!Box (used for verification)")
flag.StringVar(&config.email, "email", "", "Mail address to use for registration at Let's Encrypt")
flag.StringVar(&config.dnsResolver, "dns-resolver", "", "Resolver to use for recursive DNS queries, supported format: host:port; defaults to system resolver")
flag.StringVar(&verificationHost, "verification-url", "", "URL to use for certificate validation (defaults to 'host')")

// manual mode
flag.StringVar(&config.fullchain, "fullchain", "", "path to full certificate chain")
Expand Down Expand Up @@ -197,11 +197,17 @@ func setupConfiguration() (config configOptions) {
url.User = nil
config.host = url.String()

if config.tlsPort == 0 && url.Port() != "" {
config.tlsPort, err = strconv.Atoi(url.Port())
if verificationHost == "" {
verificationHost = config.host

config.verificationURL, err = url.Parse(config.host)
if err != nil {
log.Fatal(err)
}

if config.verificationURL.Scheme == "http" {
config.verificationURL.Scheme = "https"
}
}

if config.adminPassword == "" {
Expand Down

0 comments on commit 51ff3c1

Please sign in to comment.