-
Notifications
You must be signed in to change notification settings - Fork 0
/
dwklint.go
135 lines (120 loc) · 3.12 KB
/
dwklint.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 dwklint
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/csv"
"encoding/hex"
"fmt"
"os"
"strings"
)
type DebianWeakKeyStatus int
const (
// Pass:
NotWeak DebianWeakKeyStatus = iota
UnknownButTLSBRExceptionGranted
// Fail:
Weak
Unknown
Error
)
var blocklists map[string]*map[[sha256.Size]byte]struct{}
// Load Debian weak key blocklists from the given directory, which should contain the CSV files from https://github.com/CVE-2008-0166/dwk_blocklists
func LoadBlocklists(dwkBlocklistPath string) error {
// Initialize the map of blocklists.
blocklists = make(map[string]*map[[sha256.Size]byte]struct{})
// Find all files in the directory.
if files, err := os.ReadDir(dwkBlocklistPath); err != nil {
return err
} else {
// Loop through all files in the directory.
for _, file := range files {
// Parse the filename to determine the blocklist type and key size/curve.
var blType, keyDetail string
filename := strings.ReplaceAll(file.Name(), "_", " ")
filename = strings.ReplaceAll(filename, ".", " ")
if n, _ := fmt.Sscanf(filename, "sha256 %s %s csv", &blType, &keyDetail); n != 2 {
continue // Not a blocklist.
}
// Determine the blocklist name.
blName := ""
switch blType {
case "modulus":
blName = "RSA-" + keyDetail
case "xcoord":
switch keyDetail {
case "secp256r1":
blName = elliptic.P256().Params().Name
case "secp384r1":
blName = elliptic.P384().Params().Name
case "secp521r1":
blName = elliptic.P521().Params().Name
default:
return fmt.Errorf("unknown curve %s", keyDetail)
}
}
// Initialize the map for this blocklist.
m := make(map[[sha256.Size]byte]struct{})
blocklists[blName] = &m
// Open the CSV blocklist file.
f, err := os.Open(dwkBlocklistPath + "/" + file.Name())
if err != nil {
return err
}
defer f.Close()
// Read the CSV file.
r := csv.NewReader(f)
r.FieldsPerRecord = 1
lines, err := r.ReadAll()
if err != nil {
return err
}
// Add each hash entry to the blocklist map.
for _, line := range lines {
if h, err := hex.DecodeString(line[0]); err != nil {
return err
} else {
var hash [sha256.Size]byte
copy(hash[:], h)
m[hash] = struct{}{}
}
}
}
return nil
}
}
func HasDebianWeakKey(cert *x509.Certificate) DebianWeakKeyStatus {
switch cert.PublicKeyAlgorithm {
case x509.RSA:
if r, ok := cert.PublicKey.(*rsa.PublicKey); !ok {
return Error
} else if bl, ok := blocklists[fmt.Sprintf("RSA-%d", r.N.BitLen())]; !ok {
if r.N.BitLen() > 8192 {
return UnknownButTLSBRExceptionGranted
} else {
return Unknown
}
} else if _, ok := (*bl)[sha256.Sum256(r.N.Bytes())]; ok {
return Weak
} else {
return NotWeak
}
case x509.ECDSA:
if e, ok := cert.PublicKey.(*ecdsa.PublicKey); !ok {
return Error
} else if p := e.Params(); p == nil {
return Error
} else if bl, ok := blocklists[p.Name]; !ok {
return Unknown
} else if _, ok := (*bl)[sha256.Sum256(e.X.Bytes())]; ok {
return Weak
} else {
return NotWeak
}
default:
return Unknown
}
}