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
|
package signature
import (
"bytes"
"io"
"reflect"
"github.com/foxboron/go-uefi/efi/util"
"github.com/pkg/errors"
)
// SignatureDatabase is a list of EFI signature lists
type SignatureDatabase []*SignatureList
var ErrNotFoundSigList = errors.New("signature list not found")
func NewSignatureDatabase() *SignatureDatabase {
return &SignatureDatabase{}
}
// Checks if all signatures in a list is present in the signature database
func (sd *SignatureDatabase) SigDataExists(certtype util.EFIGUID, sigdata *SignatureData) bool {
for _, sdsiglist := range *sd {
if ok, _ := sdsiglist.Exists(sigdata); ok {
return true
}
}
return false
}
// Checks if all signatures in a list is present in the signature database
func (sd *SignatureDatabase) Exists(certtype util.EFIGUID, siglist *SignatureList) bool {
for _, sdsiglist := range *sd {
if !sdsiglist.CmpHeader(siglist) {
continue
}
return sdsiglist.ExistsInList(siglist)
}
return false
}
// Checks if the bytes in a list is present in the signature database
func (sd *SignatureDatabase) BytesExists(certtype util.EFIGUID, owner util.EFIGUID, data []byte) bool {
return sd.SigDataExists(certtype, &SignatureData{Owner: owner, Data: data})
}
// Appends the raw signature values to the database
func (sd *SignatureDatabase) Append(certtype util.EFIGUID, owner util.EFIGUID, data []byte) error {
if _, ok := ValidEFISignatureSchemes[certtype]; !ok {
return ErrNoSuchSignatureScheme
}
for _, l := range *sd {
if !util.CmpEFIGUID(l.SignatureType, certtype) {
continue
}
size := uint32(len(data)) + util.SizeofEFIGUID
if size != l.Size {
continue
}
if err := l.AppendSignature(SignatureData{Owner: owner, Data: data}); err != nil {
return err
}
return nil
}
sl := NewSignatureList(certtype)
if err := sl.AppendBytes(owner, data); err != nil {
return err
}
*sd = append(*sd, sl)
return nil
}
// Appends a signaure to the database. It will scan the database for the appropriate list to append
// itself to.
func (sd *SignatureDatabase) AppendSignature(certtype util.EFIGUID, sl *SignatureData) error {
return sd.Append(certtype, sl.Owner, sl.Data)
}
// Appends a signature list to the database
// TODO: Should merge towards a fitting list?
func (sd *SignatureDatabase) AppendList(sl *SignatureList) {
*sd = append(*sd, sl)
}
// Appends a signature database
func (sd *SignatureDatabase) AppendDatabase(s *SignatureDatabase) {
for _, list := range *s {
sd.AppendList(list)
}
}
// Remove the raw signature values to the database
func (sd *SignatureDatabase) Remove(certtype util.EFIGUID, owner util.EFIGUID, data []byte) error {
// We might want to differentiate between not finding a list for the type and
// not finding appropriate sigdata in the different lists.
nosigdata := false
for _, l := range *sd {
if !util.CmpEFIGUID(l.SignatureType, certtype) {
continue
}
size := uint32(len(data)) + util.SizeofEFIGUID
if size != l.Size {
continue
}
if err := l.RemoveBytes(owner, data); errors.Is(err, ErrNotFoundSigData) {
nosigdata = true
continue
}
if len(l.Signatures) == 0 {
return sd.RemoveList(l)
}
return nil
}
if nosigdata {
return ErrNotFoundSigData
}
return ErrNotFoundSigList
}
// Removes a signaure to the database. It will scan available lists for something to remove
func (sd *SignatureDatabase) RemoveSignature(certtype util.EFIGUID, sl *SignatureData) error {
return sd.Remove(certtype, sl.Owner, sl.Data)
}
func (sd *SignatureDatabase) removeslice(index int) {
if len(*sd) == 1 {
*sd = SignatureDatabase{}
return
}
*sd = append((*sd)[:index], (*sd)[index+1:]...)
}
// Removes a signature list from the database
func (sd *SignatureDatabase) RemoveList(sl *SignatureList) error {
for index, siglist := range *sd {
if reflect.DeepEqual(sl, siglist) {
sd.removeslice(index)
return nil
}
}
return ErrNotFoundSigList
}
// Serialize the Signature Database into bytes
func (sd *SignatureDatabase) Bytes() []byte {
buf := new(bytes.Buffer)
WriteSignatureDatabase(buf, *sd)
return buf.Bytes()
}
func (sd *SignatureDatabase) Marshal(b *bytes.Buffer) {
WriteSignatureDatabase(b, *sd)
}
func (sd *SignatureDatabase) Unmarshal(b *bytes.Buffer) error {
s, err := ReadSignatureDatabase(b)
if err != nil {
return err
}
*sd = s
return nil
}
// Write a signature database which contains a slice of SignautureLists
func WriteSignatureDatabase(b io.Writer, sigdb SignatureDatabase) {
for _, l := range sigdb {
WriteSignatureList(b, *l)
}
}
// Reads several signature lists from a io.Reader. It assumes io.EOF means there
// are no more signatures to read as opposed to an actual issue
func ReadSignatureDatabase(f io.Reader) (SignatureDatabase, error) {
siglist := []*SignatureList{}
for {
sig, err := ReadSignatureList(f)
if errors.Is(err, io.EOF) {
break
} else if err != nil {
return siglist, errors.Wrapf(err, "failed to parse signature lists")
}
siglist = append(siglist, sig)
}
return siglist, nil
}
|