-
Notifications
You must be signed in to change notification settings - Fork 1
/
ocsp_status.go
206 lines (169 loc) · 6.59 KB
/
ocsp_status.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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
// Package main provides the main command line functionality
package main
import (
"crypto"
"flag"
"fmt"
"github.com/googleinterns/ocsp-response-linter/linter"
"github.com/googleinterns/ocsp-response-linter/ocsptools"
"github.com/googleinterns/ocsp-response-linter/ocsptools/helpers"
"golang.org/x/crypto/ocsp"
"net/http"
"strings"
)
// checkFromFile takes a path to an OCSP Response file and then reads, parses, and lints it
func checkFromFile(tools ocsptools.ToolsInterface, linter linter.LinterInterface, respFile string, issuerFile string, verbose bool) error {
ocspResp, err := tools.ReadOCSPResp(respFile)
if err != nil {
return err
}
issuerCert, err := tools.ParseCertificateFile(issuerFile)
if err != nil {
return fmt.Errorf("Error parsing certificate from certificate file: %w", err)
}
linter.LintOCSPResp(ocspResp, issuerCert, verbose)
return nil
}
// checkFromCert takes a path to an ASN.1 DER encoded certificate file and
// constructs and sends an OCSP request then parses and lints the OCSP response
func checkFromCert(tools ocsptools.ToolsInterface, linter linter.LinterInterface, certFile string, issuerFile string, isPost bool, ocspURL string, dir string, hash crypto.Hash, verbose bool) error {
reqMethod := http.MethodGet
if isPost {
reqMethod = http.MethodPost
}
leafCert, err := tools.ParseCertificateFile(certFile)
if err != nil {
return fmt.Errorf("Error parsing certificate from certificate file: %w", err)
}
issuerCert, err := tools.ParseCertificateFile(issuerFile)
if err != nil {
return fmt.Errorf("Error parsing certificate from certificate file: %w", err)
}
h := helpers.Helpers{}
if issuerCert == nil {
issuerCert, err = tools.GetIssuerCertFromLeafCert(h, leafCert)
if err != nil {
return fmt.Errorf("Error getting issuer certificate from certificate: %w", err)
}
}
ocspResp, err := tools.FetchOCSPResp(h, ocspURL, dir, leafCert, issuerCert, reqMethod, hash)
if err != nil {
return fmt.Errorf("Error fetching OCSP response: %w", err)
}
linter.LintOCSPResp(ocspResp, leafCert, verbose)
return nil
}
// checkFromURL takes a server URL and constructs and sends an OCSP request to
// check that URL's certificate then parses and lints the OCSP response
func checkFromURL(tools ocsptools.ToolsInterface, linter linter.LinterInterface, serverURL string, issuerFile string, shouldPrint bool, isPost bool, noStaple bool, ocspURL string, dir string, hash crypto.Hash, verbose bool) error {
certChain, ocspResp, err := tools.GetCertChainAndStapledResp(serverURL)
if err != nil {
return err
}
leafCert := certChain[0] // the certificate we want to send to the CA
issuerCert, err := tools.ParseCertificateFile(issuerFile)
if err != nil {
return fmt.Errorf("Error parsing certificate from certificate file: %w", err)
}
h := helpers.Helpers{}
if issuerCert == nil {
issuerCert, err = tools.GetIssuerCertFromLeafCert(h, leafCert)
if err != nil {
fmt.Println("Couldn't get issuer certificate from leaf certificate, taking the second certificate in the chain as the issuer certificate")
issuerCert = certChain[1]
}
}
if shouldPrint {
err = ocsptools.PrintCert(leafCert)
if err != nil {
return fmt.Errorf("Error printing certificate: %w", err)
}
}
var parsedResp *ocsp.Response
if ocspResp == nil || noStaple {
reqMethod := http.MethodGet
if isPost {
reqMethod = http.MethodPost
}
h := helpers.Helpers{}
parsedResp, err = tools.FetchOCSPResp(h, ocspURL, dir, leafCert, issuerCert, reqMethod, hash)
if err != nil {
return fmt.Errorf("Error fetching OCSP response: %w", err)
}
} else {
fmt.Println("Stapled OCSP Response")
parsedResp, err = ocsp.ParseResponse(ocspResp, issuerCert)
if err != nil {
return fmt.Errorf("Error parsing OCSP response: %w", err)
}
}
linter.LintOCSPResp(parsedResp, leafCert, verbose)
return nil
}
// main parses the users commandline arguments & flags and then runs the appropriate functions
func main() {
// TODO: extract flag descriptions into constants?
inresp := flag.Bool("inresp", false, "Whether to read in an OCSP responses or not")
incert := flag.Bool("incert", false, "Whether to read in certificate files or not")
issuerFile := flag.String("issuercert", "", "Space separated list of issuing certificate files")
ocspurl := flag.String("ocspurl", "", "Space separated list of OCSP urls to send requests to, default fetch from certificate")
shouldPrint := flag.Bool("print", false, "Whether to print certificate or not") // may remove this print flag
isPost := flag.Bool("usepost", false, "Whether to use POST for OCSP request")
dir := flag.String("dir", "", "Where to write OCSP response")
noStaple := flag.Bool("nostaple", false, "Whether to send an OCSP request regardless of if there is a stapled OCSP response")
verbose := flag.Bool("verbose", false, "Whether to use verbose printing for printing lints")
flag.Parse()
tools := ocsptools.Tools{}
linter := linter.Linter{}
if *inresp && *incert {
panic("This tool can only parse one file format at a time. Please use only one of -inresp or -incert.")
}
var issuerFiles []string
if *issuerFile != "" {
issuerFiles = strings.Split(*issuerFile, " ")
}
var ocspURLs []string
if *ocspurl != "" {
ocspURLs = strings.Split(*ocspurl, " ")
}
args := flag.Args()
for idx, arg := range args {
iFile := ""
if idx < len(issuerFiles) {
iFile = issuerFiles[idx]
}
ocspURL := ""
if idx < len(ocspURLs) {
ocspURL = ocspURLs[idx]
}
if *inresp {
// arg is a respFile
err := checkFromFile(tools, linter, arg, iFile, *verbose)
if err != nil {
fmt.Printf("Error checking OCSP Response file %s: %s \n\n", arg, err.Error())
}
} else if *incert {
// arg is a certFile
err := checkFromCert(tools, linter, arg, iFile, *isPost, ocspURL, *dir, crypto.SHA256, *verbose)
if err == nil {
continue
}
fmt.Printf("Validation failed for sending OCSP Request encoded with SHA256: %s \n\n", err.Error())
err = checkFromCert(tools, linter, arg, iFile, *isPost, ocspURL, *dir, crypto.SHA1, *verbose)
if err != nil {
fmt.Printf("Error checking certificate file %s: %s \n\n", arg, err.Error())
}
} else {
// arg is a serverURL
err := checkFromURL(tools, linter, arg, iFile, *shouldPrint, *isPost, *noStaple, ocspURL, *dir, crypto.SHA256, *verbose)
if err == nil {
continue
}
fmt.Printf("Validation failed for sending OCSP Request encoded with SHA256: %s \n\n", err.Error())
err = checkFromURL(tools, linter, arg, iFile, *shouldPrint, *isPost, *noStaple, ocspURL, *dir, crypto.SHA1, *verbose)
if err != nil {
fmt.Printf("Error checking server URL %s: %s \n\n", arg, err.Error())
}
}
}
}