From 8bab8ad53ae6c5190e57956594b7dcadaa97667d Mon Sep 17 00:00:00 2001
From: Massimiliano Adamo <maxadamo@gmail.com>
Date: Tue, 1 Dec 2020 19:20:10 +0100
Subject: [PATCH] addedd private key check

---
 build.sh |  5 +++--
 main.go  | 61 +++++++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 57 insertions(+), 9 deletions(-)

diff --git a/build.sh b/build.sh
index dedb0e2..74c6d61 100755
--- a/build.sh
+++ b/build.sh
@@ -22,13 +22,14 @@ run_upx() {
 }
 
 rm -rf ${GOPATH}/src/github.com/maxadamo/${BIN_NAME} ${GOPATH}/src/gitlab.geant.net/devops/${BIN_NAME}
-go get -ldflags "-s -w -X main.appVersion=${PROG_VERSION} -X main.buildTime=${BUILDTIME}" gitlab.geant.net/devops/${BIN_NAME}
-#go get -ldflags "-s -w -X main.appVersion=${PROG_VERSION} -X main.buildTime=${BUILDTIME}" .
+#go get -ldflags "-s -w -X main.appVersion=${PROG_VERSION} -X main.buildTime=${BUILDTIME}" gitlab.geant.net/devops/${BIN_NAME}
+go get -ldflags "-s -w -X main.appVersion=${PROG_VERSION} -X main.buildTime=${BUILDTIME}" .
 if [ $? -gt 0 ]; then
     echo -e "\nthere was an error while compiling the code\n"
     exit
 fi
 echo ""
+
 while true; do
     read -p "Do you wish to run upx against ${BIN_NAME}? (y/n) " yn
     case $yn in
diff --git a/main.go b/main.go
index ddb2b8c..7d639a4 100644
--- a/main.go
+++ b/main.go
@@ -7,6 +7,7 @@ import (
 	"io/ioutil"
 	"net/http"
 	"os"
+	"os/exec"
 	"os/user"
 	"path/filepath"
 	"runtime"
@@ -38,6 +39,7 @@ var (
 	tmpCaDestination          string
 	tmpKeyDestination         string
 	certTmpDir                string
+	opensslBinary             string
 )
 
 // app clean and exit
@@ -54,7 +56,7 @@ func appExit(status int) {
 }
 
 // check certificates
-func checkCerificates(dnsname string, certificate string, fullchain string, ca string, key string, days int, fail bool) bool {
+func checkCertificates(dnsname string, certificate string, fullchain string, ca string, key string, days int, fail bool) bool {
 
 	Seconds := days * 86400
 	daysNumber := time.Now().Local().Add(time.Second * time.Duration(Seconds))
@@ -164,6 +166,42 @@ func checkCerificates(dnsname string, certificate string, fullchain string, ca s
 
 }
 
+// check if priv key matches the publick key
+func checkPrivkey(privkey string, pubcert string, opensslbinary string, fail bool, silent bool) bool {
+	_, errOpenssl := exec.Command(opensslbinary, "help").Output()
+	if errOpenssl != nil {
+		fmt.Printf("[WARN] skipping private key matching check: please install OpenSSL: %v\n", errOpenssl)
+	} else {
+		certPubKey, errCertPubKey := exec.Command(opensslbinary, "x509", "-noout", "-pubkey", "-in", pubcert).Output()
+		if errCertPubKey != nil {
+			if fail == true {
+				fmt.Printf("[ERR] running openssl against %s: %s\n", pubcert, errCertPubKey)
+				appExit(255)
+			} else {
+				return false
+			}
+		}
+		certPrivKey, errCertPrivKey := exec.Command(opensslbinary, "pkey", "-pubout", "-in", privkey).Output()
+		if errCertPrivKey != nil {
+			if fail == true {
+				fmt.Printf("[ERR] running openssl against %s: %s\n", privkey, errCertPrivKey)
+				appExit(255)
+			} else {
+				return false
+			}
+		}
+		pubkeyOutput := string(certPubKey[:])
+		privkeyOutput := string(certPrivKey[:])
+		if pubkeyOutput != privkeyOutput {
+			if fail == true {
+				fmt.Printf("[ERR] the private key %v does not match the the public certificate %v\n", privkey, pubcert)
+				appExit(255)
+			}
+		}
+	}
+	return true
+}
+
 // get redis key
 func GetRedisKey(redisurl string, redistoken string) string {
 	client := &http.Client{}
@@ -293,7 +331,7 @@ func main() {
   - fetches and stores a given Certificate, Full Chain, CA and Private Key
 
 Usage:
-  acme-downloader --redis-token=REDISTOKEN --vault-token=VAULTTOKEN --cert-name=CERTNAME --team-name=TEAMNAME [--days=DAYS] [--type=TYPE] [--cert-destination=CERTDESTINATION] [--fullchain-destination=FULLCHAINDESTINATION] [--key-destination=KEYDESTINATION] [--ca-destination=CADESTINATION]
+  acme-downloader --redis-token=REDISTOKEN --vault-token=VAULTTOKEN --cert-name=CERTNAME --team-name=TEAMNAME [--silent] [--days=DAYS] [--type=TYPE] [--cert-destination=CERTDESTINATION] [--fullchain-destination=FULLCHAINDESTINATION] [--key-destination=KEYDESTINATION] [--ca-destination=CADESTINATION]
   acme-downloader -v | --version
   acme-downloader -b | --build
   acme-downloader -h | --help
@@ -302,6 +340,7 @@ Options:
   -h --help                                     Show this screen
   -v --version                                  Print version exit
   -b --build                                    Print version and build information and exit
+  -s --silent                                   Suppress warnings
   --redis-token=REDISTOKEN                      Redis access token
   --vault-token=VAULTTOKEN                      Vault access token
   --cert-name=CERTNAME                          Certificate name
@@ -320,21 +359,27 @@ Options:
 		fmt.Printf("acme-downloader version: %v, built on: %v\n", appVersion, buildTime)
 		appExit(0)
 	}
+	silent := false
+	if arguments["--silent"] == true {
+		silent = true
+	}
 
 	if runtime.GOOS == "windows" {
+		opensslBinary = "openssl.exe"
 		tmpCertificateDestination = "C:\\tmp\\acme-downloader\\cert\\amce_cert.pem"
 		tmpFullchainDestination = "C:\\tmp\\acme-downloader\\cert\\amce_fullchain.pem"
 		tmpCaDestination = "C:\\tmp\\acme-downloader\\cert\\amce_ca.pem"
 		tmpKeyDestination = "C:\\tmp\\acme-downloader\\key\\amce_key.pem"
 		GroupID = 0 // just a fake one
 	} else {
+		opensslBinary = "openssl"
 		tmpCertificateDestination = "/tmp/acme-downloader/cert/amce_cert.pem"
 		tmpFullchainDestination = "/tmp/acme-downloader/cert/amce_fullchain.pem"
 		tmpCaDestination = "/tmp/acme-downloader/cert/amce_ca.pem"
 		tmpKeyDestination = "/tmp/acme-downloader/key/amce_key.pem"
 		group, groupErr := user.LookupGroup(GroupName)
 		if groupErr != nil {
-			fmt.Printf("[ERR] Fail looking up %v user user info", GroupName)
+			fmt.Printf("[ERR] Fail looking up %v user user info\n", GroupName)
 			appExit(255)
 		}
 		GroupID, _ = strconv.Atoi(group.Gid)
@@ -381,9 +426,10 @@ Options:
 	}
 
 	// check if there is a certificate installed and it is valid
-	existingCert := checkCerificates(CertName, certificateDestination, fullchainDestination, caDestination, keyDestination, Days, false)
-	if existingCert == true {
-		fmt.Printf("[INFO] the certificates are still valid\n")
+	existingCert := checkCertificates(CertName, certificateDestination, fullchainDestination, caDestination, keyDestination, Days, false)
+	existingKey := checkPrivkey(keyDestination, certificateDestination, opensslBinary, false, silent)
+	if existingCert == true && existingKey == true {
+		fmt.Printf("[INFO] the certificate is still valid\n")
 		appExit(0)
 	}
 	certificate := GetRedisKey(RedisCertURL, RedisToken)
@@ -397,7 +443,8 @@ Options:
 	WriteToFile(ca, tmpCaDestination, 0644)
 	WriteToFile(privKey, tmpKeyDestination, 0640)
 
-	checkCerificates(CertName, tmpCertificateDestination, tmpFullchainDestination, tmpCaDestination, tmpKeyDestination, Days, true)
+	checkCertificates(CertName, tmpCertificateDestination, tmpFullchainDestination, tmpCaDestination, tmpKeyDestination, Days, true)
+	checkPrivkey(keyDestination, tmpCertificateDestination, opensslBinary, false, silent)
 
 	// move certificates in place
 	moveFile(tmpCertificateDestination, certificateDestination, GroupID, 0644, 0755)
-- 
GitLab