mirror of https://github.com/namecoin/ncdns
Use new certinject package
The following defaults have unfortunately changed as a result, and will need to be set in ncdns.conf: capi.physical-store capi.set-magic-name capi.expirable-magic-namepull/149/head
parent
275374c1c2
commit
9c865846be
@ -1,17 +0,0 @@
|
|||||||
package certinject
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/hlandau/xlog"
|
|
||||||
"gopkg.in/hlandau/easyconfig.v1/cflag"
|
|
||||||
)
|
|
||||||
|
|
||||||
var log, Log = xlog.New("ncdns.certinject")
|
|
||||||
|
|
||||||
var (
|
|
||||||
flagGroup = cflag.NewGroup(nil, "certstore")
|
|
||||||
nssFlag = cflag.Bool(flagGroup, "nss", false, nssExplain)
|
|
||||||
certExpirePeriod = cflag.Int(flagGroup, "expire", 60*30, "Duration "+
|
|
||||||
"(in seconds) after which TLS certs will be removed from the "+
|
|
||||||
"trust store. Making this smaller than the DNS TTL (default "+
|
|
||||||
"600) may cause TLS errors.")
|
|
||||||
)
|
|
@ -1,11 +0,0 @@
|
|||||||
package certinject
|
|
||||||
|
|
||||||
var (
|
|
||||||
nssExplain = "Synchronize TLS certs to an NSS sqlite3 trust store? " +
|
|
||||||
"This enables HTTPS to work with NSS web browsers such as " +
|
|
||||||
"Chromium/Chrome. Only use if you've set up NUMS HPKP in " +
|
|
||||||
"Chromium/Chrome as per documentation. If you haven't set " +
|
|
||||||
"up NUMS HPKP, or if you access the configured NSS sqlite3 " +
|
|
||||||
"trust store from browsers not based on Chromium, this is " +
|
|
||||||
"unsafe and should not be used."
|
|
||||||
)
|
|
@ -1,10 +0,0 @@
|
|||||||
// +build !linux
|
|
||||||
|
|
||||||
package certinject
|
|
||||||
|
|
||||||
var (
|
|
||||||
nssExplain = "(Unsafe and experimental!) Synchronize TLS certs to " +
|
|
||||||
"an NSS sqlite3 trust store? This enables HTTPS to work " +
|
|
||||||
"with some NSS-based software. This is currently unsafe " +
|
|
||||||
"and should not be used."
|
|
||||||
)
|
|
@ -1,24 +0,0 @@
|
|||||||
// +build !windows
|
|
||||||
|
|
||||||
package certinject
|
|
||||||
|
|
||||||
// This package is used to add and remove certificates to the system trust
|
|
||||||
// store.
|
|
||||||
// Currently only supports NSS sqlite3 stores.
|
|
||||||
|
|
||||||
// InjectCert injects the given cert into all configured trust stores.
|
|
||||||
func InjectCert(derBytes []byte) {
|
|
||||||
|
|
||||||
if nssFlag.Value() {
|
|
||||||
injectCertNss(derBytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CleanCerts cleans expired certs from all configured trust stores.
|
|
||||||
func CleanCerts() {
|
|
||||||
|
|
||||||
if nssFlag.Value() {
|
|
||||||
cleanCertsNss()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
package certinject
|
|
||||||
|
|
||||||
import (
|
|
||||||
"gopkg.in/hlandau/easyconfig.v1/cflag"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This package is used to add and remove certificates to the system trust
|
|
||||||
// store.
|
|
||||||
// Currently only supports Windows CryptoAPI and NSS sqlite3 stores.
|
|
||||||
|
|
||||||
var (
|
|
||||||
cryptoApiFlag = cflag.Bool(flagGroup, "cryptoapi", false,
|
|
||||||
"Synchronize TLS certs to the CryptoAPI trust store? This "+
|
|
||||||
"enables HTTPS to work with Chromium/Chrome. Only "+
|
|
||||||
"use if you've set up NUMS HPKP in Chromium/Chrome "+
|
|
||||||
"as per documentation. If you haven't set up NUMS "+
|
|
||||||
"HPKP, or if you access ncdns from browsers not "+
|
|
||||||
"based on Chromium or Firefox, this is unsafe and "+
|
|
||||||
"should not be used.")
|
|
||||||
)
|
|
||||||
|
|
||||||
// InjectCert injects the given cert into all configured trust stores.
|
|
||||||
func InjectCert(derBytes []byte) {
|
|
||||||
|
|
||||||
if cryptoApiFlag.Value() {
|
|
||||||
injectCertCryptoApi(derBytes)
|
|
||||||
}
|
|
||||||
if nssFlag.Value() {
|
|
||||||
injectCertNss(derBytes)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CleanCerts cleans expired certs from all configured trust stores.
|
|
||||||
func CleanCerts() {
|
|
||||||
|
|
||||||
if cryptoApiFlag.Value() {
|
|
||||||
cleanCertsCryptoApi()
|
|
||||||
}
|
|
||||||
if nssFlag.Value() {
|
|
||||||
cleanCertsNss()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,192 +0,0 @@
|
|||||||
package certinject
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/sha1"
|
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
"math"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/sys/windows/registry"
|
|
||||||
)
|
|
||||||
|
|
||||||
// In 64-bit Windows, this key is shared between 64-bit and 32-bit applications.
|
|
||||||
// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa384253.aspx
|
|
||||||
const cryptoApiCertStoreRegistryBase = registry.LOCAL_MACHINE
|
|
||||||
const cryptoApiCertStoreRegistryKey = `SOFTWARE\Microsoft\EnterpriseCertificates\Root\Certificates`
|
|
||||||
const cryptoApiMagicName = "Namecoin"
|
|
||||||
const cryptoApiMagicValue = 1
|
|
||||||
|
|
||||||
func injectCertCryptoApi(derBytes []byte) {
|
|
||||||
|
|
||||||
// Format documentation of Microsoft's "Certificate Registry Blob":
|
|
||||||
|
|
||||||
// 5c 00 00 00 // propid
|
|
||||||
// 01 00 00 00 // unknown (possibly a version or flags field; value is always the same in my testing)
|
|
||||||
// 04 00 00 00 // size (little endian)
|
|
||||||
// subject public key bit length // data[size]
|
|
||||||
|
|
||||||
// 19 00 00 00
|
|
||||||
// 01 00 00 00
|
|
||||||
// 10 00 00 00
|
|
||||||
// MD5 of ECC pubkey of certificate
|
|
||||||
|
|
||||||
// 0f 00 00 00
|
|
||||||
// 01 00 00 00
|
|
||||||
// 20 00 00 00
|
|
||||||
// Signature Hash
|
|
||||||
|
|
||||||
// 03 00 00 00
|
|
||||||
// 01 00 00 00
|
|
||||||
// 14 00 00 00
|
|
||||||
// Cert SHA1 hash
|
|
||||||
|
|
||||||
// 14 00 00 00
|
|
||||||
// 01 00 00 00
|
|
||||||
// 14 00 00 00
|
|
||||||
// Key Identifier
|
|
||||||
|
|
||||||
// 04 00 00 00
|
|
||||||
// 01 00 00 00
|
|
||||||
// 10 00 00 00
|
|
||||||
// Cert MD5 hash
|
|
||||||
|
|
||||||
// 20 00 00 00
|
|
||||||
// 01 00 00 00
|
|
||||||
// cert length
|
|
||||||
// cert
|
|
||||||
|
|
||||||
// But, guess what? All you need is the "20" record.
|
|
||||||
// Windows will happily regenerate all the others for you, whenever you actually try to use the certificate.
|
|
||||||
// How cool is that?
|
|
||||||
|
|
||||||
// Length of cert
|
|
||||||
certLength := len(derBytes)
|
|
||||||
|
|
||||||
// Header for a stripped Windows Certificate Registry Blob
|
|
||||||
certBlobHeader := []byte{0x20, 0, 0, 0, 0x01, 0, 0, 0, byte((certLength >> 0) & 0xFF), byte((certLength >> 8) & 0xFF), byte((certLength >> 16) & 0xFF), byte((certLength >> 24) & 0xFF)}
|
|
||||||
|
|
||||||
// Construct the Blob
|
|
||||||
certBlob := append(certBlobHeader, derBytes...)
|
|
||||||
|
|
||||||
// Open up the cert store.
|
|
||||||
certStoreKey, err := registry.OpenKey(cryptoApiCertStoreRegistryBase, cryptoApiCertStoreRegistryKey, registry.ALL_ACCESS)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Couldn't open cert store: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer certStoreKey.Close()
|
|
||||||
|
|
||||||
// Windows CryptoAPI uses the SHA-1 fingerprint to identify a cert.
|
|
||||||
// This is probably a Bad Thing (TM) since SHA-1 is weak.
|
|
||||||
// However, that's Microsoft's problem to fix, not ours.
|
|
||||||
fingerprint := sha1.Sum(derBytes)
|
|
||||||
|
|
||||||
// Windows CryptoAPI uses a hex string to represent the fingerprint.
|
|
||||||
fingerprintHex := hex.EncodeToString(fingerprint[:])
|
|
||||||
|
|
||||||
// Windows CryptoAPI uses uppercase hex strings
|
|
||||||
fingerprintHexUpper := strings.ToUpper(fingerprintHex)
|
|
||||||
|
|
||||||
// Create the registry key in which we will store the cert.
|
|
||||||
// The 2nd result of CreateKey is openedExisting, which tells us if the cert already existed.
|
|
||||||
// This doesn't matter to us. If true, the "last modified" metadata won't update,
|
|
||||||
// but we delete and recreate the magic value inside it as a workaround.
|
|
||||||
certKey, _, err := registry.CreateKey(certStoreKey, fingerprintHexUpper, registry.ALL_ACCESS)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Couldn't create registry key for certificate: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer certKey.Close()
|
|
||||||
|
|
||||||
// Add a magic value which indicates that the certificate is a
|
|
||||||
// Namecoin cert. This will be used for deleting expired certs.
|
|
||||||
// However, we have to delete it before we create it, so that we make sure that the "last modified" metadata gets updated.
|
|
||||||
// If an error occurs during deletion, we ignore it, since it probably just means it wasn't there already.
|
|
||||||
_ = certKey.DeleteValue(cryptoApiMagicName)
|
|
||||||
err = certKey.SetDWordValue(cryptoApiMagicName, cryptoApiMagicValue)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Couldn't set magic registry value for certificate: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the registry value which holds the certificate.
|
|
||||||
err = certKey.SetBinaryValue("Blob", certBlob)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Couldn't set blob registry value for certificate: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func cleanCertsCryptoApi() {
|
|
||||||
|
|
||||||
// Open up the cert store.
|
|
||||||
certStoreKey, err := registry.OpenKey(cryptoApiCertStoreRegistryBase, cryptoApiCertStoreRegistryKey, registry.ALL_ACCESS)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Couldn't open cert store: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer certStoreKey.Close()
|
|
||||||
|
|
||||||
// get all subkey names in the cert store
|
|
||||||
subKeys, err := certStoreKey.ReadSubKeyNames(0)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Couldn't list certs in cert store: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// for all certs in the cert store
|
|
||||||
for _, subKeyName := range subKeys {
|
|
||||||
|
|
||||||
// Check if the cert is expired
|
|
||||||
expired, err := checkCertExpiredCryptoApi(certStoreKey, subKeyName)
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Couldn't check if cert is expired: %s", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete the cert if it's expired
|
|
||||||
if expired {
|
|
||||||
registry.DeleteKey(certStoreKey, subKeyName)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkCertExpiredCryptoApi(certStoreKey registry.Key, subKeyName string) (bool, error) {
|
|
||||||
|
|
||||||
// Open the cert
|
|
||||||
certKey, err := registry.OpenKey(certStoreKey, subKeyName, registry.ALL_ACCESS)
|
|
||||||
if err != nil {
|
|
||||||
return false, fmt.Errorf("Couldn't open cert registry key: %s", err)
|
|
||||||
}
|
|
||||||
defer certKey.Close()
|
|
||||||
|
|
||||||
// Check for magic value
|
|
||||||
isNamecoin, _, err := certKey.GetIntegerValue(cryptoApiMagicName)
|
|
||||||
if err != nil {
|
|
||||||
// Magic value wasn't found. Therefore don't consider it expired.
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
if isNamecoin != cryptoApiMagicValue {
|
|
||||||
// Magic value was found but it wasn't the one we recognize. Therefore don't consider it expired.
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get metadata about the cert key
|
|
||||||
certKeyInfo, err := certKey.Stat()
|
|
||||||
if err != nil {
|
|
||||||
return false, fmt.Errorf("Couldn't read metadata for cert registry key: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the last modified time
|
|
||||||
certKeyModTime := certKeyInfo.ModTime()
|
|
||||||
|
|
||||||
// If the cert's last modified timestamp differs too much from the current time in either direction, consider it expired
|
|
||||||
expired := math.Abs(time.Since(certKeyModTime).Seconds()) > float64(certExpirePeriod.Value())
|
|
||||||
|
|
||||||
return expired, nil
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
package certinject
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/pem"
|
|
||||||
"io/ioutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Injects a certificate by writing to a file. Might be relevant for non-CryptoAPI trust stores.
|
|
||||||
func injectCertFile(derBytes []byte, fileName string) {
|
|
||||||
|
|
||||||
pemBytes := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
|
||||||
err := ioutil.WriteFile(fileName, pemBytes, 0644)
|
|
||||||
if err != nil {
|
|
||||||
log.Errore(err, "Error writing cert!")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,136 +0,0 @@
|
|||||||
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"
|
|
||||||
|
|
||||||
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.)")
|
|
||||||
|
|
||||||
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.
|
|
||||||
cmd := exec.Command(nssCertutilName, "-d", "sql:"+nssDir.Value(), "-A",
|
|
||||||
"-t", "CP,,", "-n", nickname, "-a", "-i", path)
|
|
||||||
|
|
||||||
stdoutStderr, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func cleanCertsNss() {
|
|
||||||
|
|
||||||
if certDir.Value() == "" {
|
|
||||||
log.Fatal("Empty nsscertdir configuration.")
|
|
||||||
}
|
|
||||||
if nssDir.Value() == "" {
|
|
||||||
log.Fatal("Empty nssdbdir configuration.")
|
|
||||||
}
|
|
||||||
|
|
||||||
certFiles, err := ioutil.ReadDir(certDir.Value() + "/")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error enumerating files in cert directory: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// for all Namecoin certs in the folder
|
|
||||||
for _, f := range certFiles {
|
|
||||||
|
|
||||||
// Check if the cert is expired
|
|
||||||
expired, err := checkCertExpiredNss(f)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error checking if NSS cert is expired: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// delete the cert if it's expired
|
|
||||||
if expired {
|
|
||||||
|
|
||||||
filename := f.Name()
|
|
||||||
|
|
||||||
fingerprintHex := strings.Replace(filename, ".pem", "",
|
|
||||||
-1)
|
|
||||||
|
|
||||||
nickname := nicknameFromFingerprintHexNss(
|
|
||||||
fingerprintHex)
|
|
||||||
|
|
||||||
// Delete the cert from NSS
|
|
||||||
cmd := exec.Command(nssCertutilName, "-d", "sql:"+
|
|
||||||
nssDir.Value(), "-D", "-n", nickname)
|
|
||||||
|
|
||||||
stdoutStderr, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also delete the cert from the filesystem
|
|
||||||
err = os.Remove(certDir.Value() + "/" + filename)
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("Error deleting NSS cert from filesystem: %s", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkCertExpiredNss(certFile os.FileInfo) (bool, error) {
|
|
||||||
|
|
||||||
// Get the last modified time
|
|
||||||
certFileModTime := certFile.ModTime()
|
|
||||||
|
|
||||||
age := time.Since(certFileModTime)
|
|
||||||
ageSeconds := age.Seconds()
|
|
||||||
|
|
||||||
// If the cert's last modified timestamp differs too much from the
|
|
||||||
// current time in either direction, consider it expired
|
|
||||||
expired := math.Abs(ageSeconds) > float64(certExpirePeriod.Value())
|
|
||||||
|
|
||||||
log.Debugf("Age of certificate: %s = %f seconds; expired = %t", age, ageSeconds, expired)
|
|
||||||
|
|
||||||
return expired, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func nicknameFromFingerprintHexNss(fingerprintHex string) string {
|
|
||||||
return "Namecoin-" + fingerprintHex
|
|
||||||
}
|
|
@ -1,48 +0,0 @@
|
|||||||
package certinject
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestCheckCertExpired(t *testing.T) {
|
|
||||||
testFilename := "test_cert_file.pem"
|
|
||||||
|
|
||||||
certExpirePeriod.SetValue(5.0)
|
|
||||||
|
|
||||||
bytesDummy := []byte(`TEST DATA`)
|
|
||||||
|
|
||||||
injectCertFile(bytesDummy, testFilename)
|
|
||||||
defer os.Remove(testFilename)
|
|
||||||
|
|
||||||
info1, err := os.Stat(testFilename)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error getting file info 1: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expired1, err := checkCertExpiredNss(info1)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error checking if file info 1 expired: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if expired1 {
|
|
||||||
t.Errorf("Cert expired instantly")
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
|
|
||||||
info2, err := os.Stat(testFilename)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error getting file info 2: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
expired2, err := checkCertExpiredNss(info2)
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("Error checking if file info 2 expired: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !expired2 {
|
|
||||||
t.Errorf("Cert never expired")
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
// +build !windows
|
|
||||||
|
|
||||||
package certinject
|
|
||||||
|
|
||||||
const (
|
|
||||||
nssCertutilName = "certutil"
|
|
||||||
)
|
|
@ -1,5 +0,0 @@
|
|||||||
package certinject
|
|
||||||
|
|
||||||
const (
|
|
||||||
nssCertutilName = "nss-certutil"
|
|
||||||
)
|
|
Loading…
Reference in New Issue