2018-02-10 06:17:24 +00:00
|
|
|
package certinject
|
|
|
|
|
|
|
|
import "crypto/sha256"
|
|
|
|
import "encoding/hex"
|
|
|
|
import "io/ioutil"
|
|
|
|
import "os"
|
|
|
|
import "os/exec"
|
|
|
|
import "strings"
|
|
|
|
import "math"
|
|
|
|
import "time"
|
|
|
|
import "gopkg.in/hlandau/easyconfig.v1/cflag"
|
|
|
|
|
2018-02-14 05:03:04 +00:00
|
|
|
var certDir = cflag.String(flagGroup, "nsscertdir", "", "Directory to store "+
|
|
|
|
"certificate files. Only use a directory that only ncdns can write "+
|
|
|
|
"to. (Required if nss is set.)")
|
|
|
|
var nssDir = cflag.String(flagGroup, "nssdbdir", "", "Directory that "+
|
|
|
|
"contains NSS's cert9.db. (Required if nss is set.)")
|
2018-02-10 06:17:24 +00:00
|
|
|
|
|
|
|
func injectCertNss(derBytes []byte) {
|
|
|
|
|
|
|
|
if certDir.Value() == "" {
|
|
|
|
log.Fatal("Empty nsscertdir configuration.")
|
|
|
|
}
|
|
|
|
if nssDir.Value() == "" {
|
|
|
|
log.Fatal("Empty nssdbdir configuration.")
|
|
|
|
}
|
|
|
|
|
|
|
|
fingerprint := sha256.Sum256(derBytes)
|
|
|
|
|
|
|
|
fingerprintHex := hex.EncodeToString(fingerprint[:])
|
|
|
|
|
|
|
|
path := certDir.Value() + "/" + fingerprintHex + ".pem"
|
|
|
|
|
|
|
|
injectCertFile(derBytes, path)
|
|
|
|
|
|
|
|
nickname := nicknameFromFingerprintHexNss(fingerprintHex)
|
|
|
|
|
|
|
|
// TODO: check whether we can replace CP with just P.
|
2018-02-14 05:03:04 +00:00
|
|
|
cmd := exec.Command(nssCertutilName, "-d", "sql:"+nssDir.Value(), "-A",
|
|
|
|
"-t", "CP,,", "-n", nickname, "-a", "-i", path)
|
2018-02-10 06:17:24 +00:00
|
|
|
|
2018-02-26 11:55:13 +00:00
|
|
|
stdoutStderr, err := cmd.CombinedOutput()
|
2018-02-10 06:17:24 +00:00
|
|
|
if err != nil {
|
2018-02-26 11:55:13 +00:00
|
|
|
if strings.Contains(string(stdoutStderr), "SEC_ERROR_PKCS11_GENERAL_ERROR") {
|
|
|
|
log.Warn("Temporary SEC_ERROR_PKCS11_GENERAL_ERROR injecting certificate to NSS database; retrying in 1ms...")
|
|
|
|
time.Sleep(1 * time.Millisecond)
|
|
|
|
injectCertNss(derBytes)
|
|
|
|
} else {
|
|
|
|
log.Errorf("Error injecting cert to NSS database: %s\n%s", err, stdoutStderr)
|
|
|
|
}
|
2018-02-10 06:17:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func cleanCertsNss() {
|
|
|
|
|
|
|
|
if certDir.Value() == "" {
|
|
|
|
log.Fatal("Empty nsscertdir configuration.")
|
|
|
|
}
|
|
|
|
if nssDir.Value() == "" {
|
|
|
|
log.Fatal("Empty nssdbdir configuration.")
|
|
|
|
}
|
|
|
|
|
2018-02-26 11:55:13 +00:00
|
|
|
certFiles, err := ioutil.ReadDir(certDir.Value() + "/")
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("Error enumerating files in cert directory: %s", err)
|
|
|
|
}
|
2018-02-10 06:17:24 +00:00
|
|
|
|
|
|
|
// for all Namecoin certs in the folder
|
|
|
|
for _, f := range certFiles {
|
|
|
|
|
|
|
|
// Check if the cert is expired
|
|
|
|
expired, err := checkCertExpiredNss(f)
|
|
|
|
if err != nil {
|
2018-02-26 11:55:13 +00:00
|
|
|
log.Fatalf("Error checking if NSS cert is expired: %s", err)
|
2018-02-10 06:17:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// delete the cert if it's expired
|
|
|
|
if expired {
|
|
|
|
|
|
|
|
filename := f.Name()
|
|
|
|
|
2018-02-14 05:03:04 +00:00
|
|
|
fingerprintHex := strings.Replace(filename, ".pem", "",
|
|
|
|
-1)
|
2018-02-10 06:17:24 +00:00
|
|
|
|
2018-02-14 05:03:04 +00:00
|
|
|
nickname := nicknameFromFingerprintHexNss(
|
|
|
|
fingerprintHex)
|
2018-02-10 06:17:24 +00:00
|
|
|
|
|
|
|
// Delete the cert from NSS
|
2018-02-14 05:03:04 +00:00
|
|
|
cmd := exec.Command(nssCertutilName, "-d", "sql:"+
|
|
|
|
nssDir.Value(), "-D", "-n", nickname)
|
2018-02-10 06:17:24 +00:00
|
|
|
|
2018-02-26 11:55:13 +00:00
|
|
|
stdoutStderr, err := cmd.CombinedOutput()
|
2018-02-10 06:17:24 +00:00
|
|
|
if err != nil {
|
2018-02-26 11:55:13 +00:00
|
|
|
if strings.Contains(string(stdoutStderr), "SEC_ERROR_UNRECOGNIZED_OID") {
|
|
|
|
log.Warn("Tried to delete certificate from NSS database, but the certificate was already not present in NSS database")
|
|
|
|
} else if strings.Contains(string(stdoutStderr), "SEC_ERROR_PKCS11_GENERAL_ERROR") {
|
|
|
|
log.Warn("Temporary SEC_ERROR_PKCS11_GENERAL_ERROR deleting certificate from NSS database; retrying in 1ms...")
|
|
|
|
time.Sleep(1 * time.Millisecond)
|
|
|
|
cleanCertsNss()
|
|
|
|
} else {
|
|
|
|
log.Fatalf("Error deleting cert from NSS database: %s\n%s", err, stdoutStderr)
|
|
|
|
}
|
2018-02-10 06:17:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Also delete the cert from the filesystem
|
|
|
|
err = os.Remove(certDir.Value() + "/" + filename)
|
2018-02-14 05:03:04 +00:00
|
|
|
if err != nil {
|
2018-02-26 11:55:13 +00:00
|
|
|
log.Fatalf("Error deleting NSS cert from filesystem: %s", err)
|
2018-02-14 05:03:04 +00:00
|
|
|
}
|
2018-02-10 06:17:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func checkCertExpiredNss(certFile os.FileInfo) (bool, error) {
|
|
|
|
|
|
|
|
// Get the last modified time
|
|
|
|
certFileModTime := certFile.ModTime()
|
|
|
|
|
2018-02-26 11:55:13 +00:00
|
|
|
age := time.Since(certFileModTime)
|
|
|
|
ageSeconds := age.Seconds()
|
|
|
|
|
2018-02-14 05:03:04 +00:00
|
|
|
// If the cert's last modified timestamp differs too much from the
|
|
|
|
// current time in either direction, consider it expired
|
2018-02-26 11:55:13 +00:00
|
|
|
expired := math.Abs(ageSeconds) > float64(certExpirePeriod.Value())
|
|
|
|
|
|
|
|
log.Debugf("Age of certificate: %s = %f seconds; expired = %t", age, ageSeconds, expired)
|
2018-02-10 06:17:24 +00:00
|
|
|
|
|
|
|
return expired, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func nicknameFromFingerprintHexNss(fingerprintHex string) string {
|
|
|
|
return "Namecoin-" + fingerprintHex
|
|
|
|
}
|