-
Notifications
You must be signed in to change notification settings - Fork 0
/
reader_auth.go
151 lines (123 loc) · 3.48 KB
/
reader_auth.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
package mdoc
import (
"bytes"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/x509"
"encoding/asn1"
"errors"
"time"
"github.com/fxamacker/cbor/v2"
"github.com/veraison/go-cose"
)
var (
ErrMissingAlgorithmHeader = errors.New("missing algorithm header")
ErrUnsupportedAlgorithm = errors.New("unsupported algorithm")
ErrNoRootCertificates = errors.New("no root certificates")
ErrEmptyChain = errors.New("empty chan")
ErrInvalidReaderAuthCertificate = errors.New("invalid reader auth certificate")
)
type ReaderAuth cose.UntaggedSign1Message
func (ra *ReaderAuth) MarshalCBOR() ([]byte, error) {
return cbor.Marshal((*cose.UntaggedSign1Message)(ra))
}
func (ra *ReaderAuth) UnmarshalCBOR(data []byte) error {
return cbor.Unmarshal(data, (*cose.UntaggedSign1Message)(ra))
}
func (ra *ReaderAuth) Verify(
readerAuthenticationBytes *TaggedEncodedCBOR,
rootCertificates []*x509.Certificate,
now time.Time,
) error {
chain, err := x509Chain(ra.Headers.Unprotected)
if err != nil {
return err
}
readerAuthCertificate, err := verifyChain(
rootCertificates,
chain,
now,
nil,
nil,
checkReaderAuthenticationCertificate,
)
if err != nil {
return err
}
signatureAlgorithm, err := ra.Headers.Protected.Algorithm()
if err != nil {
return ErrMissingAlgorithmHeader
}
verifier, err := cose.NewVerifier(signatureAlgorithm, readerAuthCertificate.PublicKey)
if err != nil {
return err
}
return (*cose.Sign1Message)(ra).VerifyDetached(
readerAuthenticationBytes.TaggedValue,
[]byte{},
verifier,
)
}
func checkReaderAuthenticationCertificate(certificate *x509.Certificate, signer *x509.Certificate) error {
if certificate.Version != 3 {
return ErrInvalidReaderAuthCertificate
}
// TODO serial number, max len 20 octets
validityDuration := certificate.NotAfter.Sub(certificate.NotBefore)
if validityDuration.Hours()/24 > 1187 {
return ErrInvalidReaderAuthCertificate
}
if len(certificate.RawSubject) == 0 {
return ErrInvalidReaderAuthCertificate
}
// TODO subject public key info checks
if !bytes.Equal(certificate.AuthorityKeyId, signer.SubjectKeyId) {
return ErrInvalidReaderAuthCertificate
}
// TODO subject key identifier check
// TODO exclusive?
if certificate.KeyUsage != x509.KeyUsageDigitalSignature {
return ErrInvalidReaderAuthCertificate
}
// TODO issuer alt name
extKeyUsage := certificate.UnknownExtKeyUsage
if len(extKeyUsage) != 1 {
return ErrInvalidReaderAuthCertificate
}
if !extKeyUsage[0].Equal(asn1.ObjectIdentifier{1, 0, 18013, 5, 1, 6}) {
return ErrInvalidReaderAuthCertificate
}
// TODO CRL distribution points
// TODO authority information access
switch certificate.PublicKeyAlgorithm {
case x509.ECDSA:
_, ok := certificate.PublicKey.(*ecdsa.PublicKey)
if !ok {
return ErrInvalidReaderAuthCertificate
}
case x509.Ed25519:
_, ok := certificate.PublicKey.(*ed25519.PublicKey)
if !ok {
return ErrInvalidReaderAuthCertificate
}
default:
return ErrInvalidReaderAuthCertificate
}
return nil
}
type ReaderAuthentication struct {
_ struct{} `cbor:",toarray"`
ReaderAuthentication string
SessionTranscript SessionTranscript
ItemsRequestBytes TaggedEncodedCBOR
}
func NewReaderAuthentication(
sessionTranscript SessionTranscript,
itemsRequestBytes TaggedEncodedCBOR,
) *ReaderAuthentication {
return &ReaderAuthentication{
ReaderAuthentication: "ReaderAuthentication",
SessionTranscript: sessionTranscript,
ItemsRequestBytes: itemsRequestBytes,
}
}