You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
DateKeys/internal/cms/cmstest/edit.go

153 lines
4.7 KiB

package cmstest
import (
"bytes"
"slices"
"g.activething.com/go/DateKeys/internal/der"
)
// The edits of the DER of a signature, a token or a certificate: what an
// attacker, or a signing application of another country, does to the bytes
// after they are signed. A path lists the index of a child at each level,
// from the element given: in a signature or a token, 1, 0 is the SignedData.
// Children returns the encodings of the children of the constructed element b.
func Children(b []byte) [][]byte {
_, kids, err := der.Split(b)
if err != nil {
panic(err)
}
return kids
}
// At returns the element at path in b.
func At(b []byte, path ...int) []byte {
for _, i := range path {
b = Children(b)[i]
}
return b
}
// Edit returns b with the element at path replaced by what f returns for it,
// and the lengths of its ancestors written again. f may return nil, to remove
// the element, or several elements one after the other.
func Edit(b []byte, f func(old []byte) []byte, path ...int) []byte {
if len(path) == 0 {
return f(b)
}
kids := slices.Clone(Children(b))
kids[path[0]] = Edit(kids[path[0]], f, path[1:]...)
return tlv(b[0], kids...)
}
// Retag returns an edit that changes the identifier octet of an element.
func Retag(tag byte) func([]byte) []byte {
return func(b []byte) []byte { return append([]byte{tag}, b[1:]...) }
}
// Replace returns an edit that puts elems in the place of an element.
func Replace(elems ...[]byte) func([]byte) []byte {
return func([]byte) []byte { return bytes.Join(elems, nil) }
}
// Append returns an edit that adds elems at the end of the children of a
// constructed element.
func Append(elems ...[]byte) func([]byte) []byte {
return func(b []byte) []byte { return tlv(b[0], append(slices.Clone(Children(b)), elems...)...) }
}
// Indefinite returns the constructed element b with an indefinite length:
// BER, which DER forbids (X.690 10.1).
func Indefinite(b []byte) []byte {
c, err := der.Content(b)
if err != nil {
panic(err)
}
out := append([]byte{b[0], 0x80}, c...)
return append(out, 0, 0)
}
// SignedDataPath is the path of the SignedData in a signature or a token.
var SignedDataPath = []int{1, 0}
// SignerInfosPath returns the path of the signerInfos of the signature or the
// token b: the last field of its SignedData.
func SignerInfosPath(b []byte) []int {
return append(slices.Clone(SignedDataPath), len(Children(At(b, SignedDataPath...)))-1)
}
// sid returns the two forms of the SignerIdentifier of s.
func sid(s Signer) (issuerAndSerial, ski []byte) {
return Seq(s.Cert.RawIssuer, s.Cert.Serial), tlv(0x80, s.Cert.SubjectKeyId)
}
// editSigner applies f to the SignerInfo of s in the signature b, and removes
// it when f returns nil.
func editSigner(b []byte, s Signer, f func(info []byte) []byte) []byte {
ias, ski := sid(s)
return Edit(b, func(set []byte) []byte {
var out [][]byte
for _, info := range Children(set) {
if id := Children(info)[1]; bytes.Equal(id, ias) || s.Cert.SubjectKeyId != nil && bytes.Equal(id, ski) {
if info = f(info); info == nil {
continue
}
}
out = append(out, info)
}
return Set(0x31, out...)
}, SignerInfosPath(b)...)
}
// Withdraw returns the signature b without the SignerInfo of s: a signature
// withdrawn. Its certificate stays.
func Withdraw(b []byte, s Signer) []byte {
return editSigner(b, s, func([]byte) []byte { return nil })
}
// WithoutTimeStamp returns the signature b with the unsigned attributes of
// the SignerInfo of s removed: its CAdES-T withdrawn. What the SignerInfo
// signs does not change.
func WithoutTimeStamp(b []byte, s Signer) []byte {
return editSigner(b, s, func(info []byte) []byte {
f := Children(info)
if n := len(f); n > 0 && f[n-1][0] == 0xa1 {
f = f[:n-1]
}
return Seq(f...)
})
}
// Merge returns the co-signature that joins the signatures sigs of one
// message, as a signing application adds a SignerInfo to a signature: the
// digest algorithms and the certificates of all, each once, and their
// SignerInfo, each in DER order.
func Merge(sigs ...[]byte) []byte {
var algs, certs, infos [][]byte
var version, encap []byte
for _, s := range sigs {
f := Children(At(s, SignedDataPath...))
version, encap = f[0], f[2]
algs = append(algs, Children(f[1])...)
for _, x := range f[3:] {
switch x[0] {
case 0xa0:
certs = append(certs, Children(x)...)
case 0x31:
infos = append(infos, Children(x)...)
}
}
}
once := func(e [][]byte) [][]byte {
slices.SortFunc(e, bytes.Compare)
return slices.CompactFunc(e, bytes.Equal)
}
fields := [][]byte{version, Set(0x31, once(algs)...), encap}
if len(certs) > 0 {
fields = append(fields, Set(0xa0, once(certs)...))
}
fields = append(fields, Set(0x31, infos...))
return Seq(OID(OIDSignedData), tlv(0xa0, Seq(fields...)))
}

Powered by TurnKey Linux.