-
Notifications
You must be signed in to change notification settings - Fork 39
/
reqbuild.go
137 lines (126 loc) · 2.75 KB
/
reqbuild.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
package csblob
import (
"bytes"
"crypto/x509"
"encoding/asn1"
"encoding/binary"
)
type reqBuilder struct {
out bytes.Buffer
err error
}
func DefaultRequirement(identifier string, certs []*x509.Certificate) ([]byte, error) {
leaf := certs[0]
b := new(reqBuilder)
b.putUint32(1)
items := []func(){
b.identifier(identifier),
b.anchorAppleGeneric(),
b.certFieldEqual(0, "subject.CN", leaf.Subject.CommonName),
}
// find intermediate cert
for _, cert := range certs[1:] {
if !bytes.Equal(cert.RawSubject, leaf.RawIssuer) {
continue
}
// look for endorsement for specific signature role
for _, ext := range cert.Extensions {
if hasPrefix(ext.Id, Intermediate) {
items = append(items, b.certExtensionExists(1, ext.Id))
break
}
}
break
}
// build requirement from criteria
b.and(items...)()
if b.err != nil {
return nil, b.err
}
i := newSuperItem(csRequirement, b.out.Bytes())
i.itype = uint32(DesignatedRequirement)
return marshalSuperBlob(csRequirements, []superItem{i}), nil
}
func (b *reqBuilder) putUint32(v uint32) {
var d [4]byte
binary.BigEndian.PutUint32(d[:], v)
b.out.Write(d[:])
}
func (b *reqBuilder) putData(v []byte) {
b.putUint32(uint32(len(v)))
b.out.Write(v)
n := len(v)
for n%4 != 0 {
b.out.WriteByte(0)
n++
}
}
func (b *reqBuilder) putOID(oid asn1.ObjectIdentifier) {
// pack first two digits together
packed := append(asn1.ObjectIdentifier{oid[0]*40 + oid[1]}, oid[2:]...)
var out []byte
for _, v := range packed {
if v < 0x80 {
// simple case
out = append(out, byte(v))
continue
}
// build starting from least-significant word
var outv []byte
for {
outv = append(outv, byte(v&0x7f))
if v >= 0x80 {
v >>= 7
} else {
break
}
}
// reverse and set MSB on all but the last word
for i := len(outv) - 1; i >= 0; i-- {
vv := outv[i]
if i != 0 {
vv |= 0x80
}
out = append(out, vv)
}
}
b.putData(out)
}
func (b *reqBuilder) and(items ...func()) func() {
return func() {
for len(items) > 1 {
b.putUint32(opAnd)
items[0]()
items = items[1:]
}
items[0]()
}
}
func (b *reqBuilder) identifier(v string) func() {
return func() {
b.putUint32(opIdent)
b.putData([]byte(v))
}
}
func (b *reqBuilder) anchorAppleGeneric() func() {
return func() {
b.putUint32(opAppleGenericAnchor)
}
}
func (b *reqBuilder) certFieldEqual(slot int32, field, value string) func() {
return func() {
b.putUint32(opCertField)
b.putUint32(uint32(slot))
b.putData([]byte(field))
b.putUint32(uint32(matchEqual))
b.putData([]byte(value))
}
}
func (b *reqBuilder) certExtensionExists(slot int32, oid asn1.ObjectIdentifier) func() {
return func() {
b.putUint32(opCertGeneric)
b.putUint32(uint32(slot))
b.putOID(oid)
b.putUint32(uint32(matchExists))
}
}