-
Notifications
You must be signed in to change notification settings - Fork 5
/
nss.go
135 lines (106 loc) · 3.79 KB
/
nss.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package certinject
import (
"crypto/sha256"
"encoding/hex"
"io/ioutil"
"math"
"os"
"os/exec"
"strings"
"time"
"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()
switch {
case err == nil: // skip
case 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")
case 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()
default:
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
}