forked from devsisters/goquic
/
proof_verifier.go
140 lines (117 loc) · 3.36 KB
/
proof_verifier.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
package goquic
import "C"
import (
"bytes"
"crypto"
"crypto/ecdsa"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"errors"
"log"
"unsafe"
)
type ProofVerifier struct {
// Holds Job
jobs []*ProofVerifyJob
}
type ProofVerifyJob struct {
hostname []byte
serverConfig []byte
certSct []byte
signature []byte
certs [][]byte
}
func CreateProofVerifier() *ProofVerifier {
return &ProofVerifier{
jobs: make([]*ProofVerifyJob, 0),
}
}
var ProofSignatureLabel = []byte{'Q', 'U', 'I', 'C', ' ', 's', 'e', 'r', 'v', 'e', 'r', ' ', 'c', 'o', 'n', 'f', 'i', 'g', ' ', 's', 'i', 'g', 'n', 'a', 't', 'u', 'r', 'e', 0x00}
func (job *ProofVerifyJob) CheckSignature(cert *x509.Certificate) error {
switch pub := cert.PublicKey.(type) {
case *rsa.PublicKey:
// cert.CheckSignature() uses PKCS1v15, not PSS. So we cannot use that on RSA
h := sha256.New()
h.Write(ProofSignatureLabel)
h.Write(job.serverConfig)
if err := rsa.VerifyPSS(pub, crypto.SHA256, h.Sum(nil), job.signature, nil); err != nil {
return err
}
case *ecdsa.PublicKey:
// TODO(hodduc): TEST needed
if err := cert.CheckSignature(x509.ECDSAWithSHA256, job.serverConfig, job.signature); err != nil {
return err
}
default:
return errors.New("Unsupported Public key type")
}
return nil
}
func (job *ProofVerifyJob) Verify() bool {
leafcert, err := x509.ParseCertificate(job.certs[0])
if err != nil {
// TODO(hodduc) error chk, log chk
log.Fatal("Parsing leaf cert", err)
return false
}
if err := job.CheckSignature(leafcert); err != nil {
// TODO(hodduc) error chk, log chk
log.Fatal("Signature fail", err)
return false
}
buf := bytes.NewBuffer(nil)
for _, asn1cert := range job.certs {
buf.Write(asn1cert)
}
certs, err := x509.ParseCertificates(buf.Bytes())
if err != nil {
// TODO(hodduc) error chk, log chk
log.Fatal("Parsing cert chain", err)
return false
}
intmPool := x509.NewCertPool()
for i := 1; i < len(certs); i++ {
intmPool.AddCert(certs[i])
}
verifyOpt := x509.VerifyOptions{
DNSName: string(job.hostname),
Intermediates: intmPool,
}
if _, err := certs[0].Verify(verifyOpt); err != nil {
log.Fatal("Verify failed", err)
return false
}
return true
}
//export NewProofVerifyJob
func NewProofVerifyJob(proof_verifier_c unsafe.Pointer,
hostname_c unsafe.Pointer, hostname_sz C.size_t,
server_config_c unsafe.Pointer, server_config_sz C.size_t,
cert_sct_c unsafe.Pointer, cert_sct_sz C.size_t,
signature_c unsafe.Pointer, signature_sz C.size_t) unsafe.Pointer {
proofVerifier := (*ProofVerifier)(proof_verifier_c)
job := &ProofVerifyJob{
hostname: C.GoBytes(hostname_c, C.int(hostname_sz)),
serverConfig: C.GoBytes(server_config_c, C.int(server_config_sz)),
certSct: C.GoBytes(cert_sct_c, C.int(cert_sct_sz)),
signature: C.GoBytes(signature_c, C.int(signature_sz)),
certs: make([][]byte, 0),
}
proofVerifier.jobs = append(proofVerifier.jobs, job)
return unsafe.Pointer(job)
}
//export ProofVerifyJobAddCert
func ProofVerifyJobAddCert(job_c unsafe.Pointer, cert_c unsafe.Pointer, cert_sz C.size_t) {
job := (*ProofVerifyJob)(job_c)
job.certs = append(job.certs, C.GoBytes(cert_c, C.int(cert_sz)))
}
//export ProofVerifyJobVerifyProof
func ProofVerifyJobVerifyProof(job_c unsafe.Pointer) C.int {
job := (*ProofVerifyJob)(job_c)
if ret := job.Verify(); ret {
return C.int(1)
} else {
return C.int(0)
}
}