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/der/der.go

196 lines
5.5 KiB

// Package der checks that bytes are one element in the Distinguished Encoding
// Rules of X.690, as spec v0.11 §29.10 asks of a CMS signature before it
// looks inside it: definite and minimal lengths, no high tag numbers, no
// constructed form of a type that DER only has primitive, canonical BOOLEAN,
// INTEGER, NULL, OBJECT IDENTIFIER and BIT STRING, and no bytes after the
// element. Go's encoding/asn1 accepts some of what DER forbids, and a
// signature that two implementations read the same must not depend on it.
//
// The order of the elements of a SET OF cannot be checked without a schema:
// SetOfSorted does it for the callers that know theirs.
package der
import (
"bytes"
"errors"
"fmt"
)
const maxDepth = 32
// Check returns nil when b is exactly one DER element.
func Check(b []byte) error {
n, err := check(b, 0)
if err != nil {
return err
}
if n != len(b) {
return fmt.Errorf("der: %d bytes after the element", len(b)-n)
}
return nil
}
// Split returns the content of the DER element b, which must be constructed,
// as the encodings of its children, and the identifier octet of b. It
// assumes Check passed.
func Split(b []byte) (id byte, children [][]byte, err error) {
if len(b) == 0 || b[0]&0x20 == 0 {
return 0, nil, errors.New("der: not a constructed element")
}
hl, cl, err := header(b)
if err != nil {
return 0, nil, err
}
rest := b[hl : hl+cl]
for len(rest) > 0 {
h, c, err := header(rest)
if err != nil {
return 0, nil, err
}
children = append(children, rest[:h+c])
rest = rest[h+c:]
}
return b[0], children, nil
}
// Content returns the content octets of the DER element b.
func Content(b []byte) ([]byte, error) {
hl, cl, err := header(b)
if err != nil {
return nil, err
}
return b[hl : hl+cl], nil
}
// SetOfSorted reports whether the encodings are in ascending order of their
// bytes, as DER requires of the elements of a SET OF (X.690 11.6), and
// without repetitions: a SET OF of this profile has none.
func SetOfSorted(elems [][]byte) bool {
for i := 1; i < len(elems); i++ {
if bytes.Compare(elems[i-1], elems[i]) >= 0 {
return false
}
}
return true
}
// header returns the length of the identifier and length octets of the
// element at the start of b, and the length of its content, which must fit
// in b.
func header(b []byte) (headerLen, contentLen int, err error) {
if len(b) < 2 {
return 0, 0, errors.New("der: truncated element")
}
if b[0]&0x1f == 0x1f {
return 0, 0, errors.New("der: a tag number of 31 or more")
}
l := b[1]
switch {
case l < 0x80:
headerLen, contentLen = 2, int(l)
case l == 0x80:
return 0, 0, errors.New("der: an indefinite length")
case l == 0xff:
return 0, 0, errors.New("der: a length of 0xff")
default:
n := int(l & 0x7f)
if n > 4 || len(b) < 2+n {
return 0, 0, errors.New("der: a length that does not fit")
}
if b[2] == 0 {
return 0, 0, errors.New("der: a length with a leading zero")
}
v := 0
for _, c := range b[2 : 2+n] {
v = v<<8 | int(c)
}
if v < 0x80 {
return 0, 0, errors.New("der: a long form for a length under 128")
}
headerLen, contentLen = 2+n, v
}
if contentLen < 0 || contentLen > len(b)-headerLen {
return 0, 0, errors.New("der: an element longer than its container")
}
return headerLen, contentLen, nil
}
// check validates the element at the start of b and returns its length.
func check(b []byte, depth int) (int, error) {
if depth > maxDepth {
return 0, errors.New("der: nested too deep")
}
hl, cl, err := header(b)
if err != nil {
return 0, err
}
content := b[hl : hl+cl]
id := b[0]
class, constructed, tag := id>>6, id&0x20 != 0, id&0x1f
if constructed {
if class == 0 && tag != 16 && tag != 17 {
return 0, fmt.Errorf("der: constructed form of the universal type %d", tag)
}
for len(content) > 0 {
n, err := check(content, depth+1)
if err != nil {
return 0, err
}
content = content[n:]
}
return hl + cl, nil
}
if class == 0 {
if err := checkPrimitive(tag, content); err != nil {
return 0, err
}
}
return hl + cl, nil
}
func checkPrimitive(tag byte, c []byte) error {
switch tag {
case 1: // BOOLEAN
if len(c) != 1 || (c[0] != 0 && c[0] != 0xff) {
return errors.New("der: a BOOLEAN that is not 00 or FF")
}
case 2, 10: // INTEGER, ENUMERATED
if len(c) == 0 {
return errors.New("der: an empty INTEGER")
}
if len(c) > 1 && (c[0] == 0 && c[1]&0x80 == 0 || c[0] == 0xff && c[1]&0x80 != 0) {
return errors.New("der: an INTEGER that is not minimal")
}
case 3: // BIT STRING
if len(c) == 0 || c[0] > 7 || len(c) == 1 && c[0] != 0 {
return errors.New("der: a malformed BIT STRING")
}
if len(c) > 1 && c[0] != 0 && c[len(c)-1]&(1<<c[0]-1) != 0 {
return errors.New("der: a BIT STRING with unused bits that are not zero")
}
case 5: // NULL
if len(c) != 0 {
return errors.New("der: a NULL with content")
}
case 6: // OBJECT IDENTIFIER
if len(c) == 0 || c[len(c)-1]&0x80 != 0 {
return errors.New("der: a malformed OBJECT IDENTIFIER")
}
start := true
for _, x := range c {
if start && x == 0x80 {
return errors.New("der: an OBJECT IDENTIFIER with a leading 0x80 in a subidentifier")
}
start = x&0x80 == 0
}
case 4, 12, 19, 20, 22, 23, 24, 26, 28, 30: // OCTET STRING and the string and time types of X.509
case 16, 17:
return fmt.Errorf("der: the universal type %d in primitive form", tag)
default:
// 0 is the end of contents of BER, and the rest are types that no
// certificate, signature or token of the profile has.
return fmt.Errorf("der: the universal type %d, which the profile does not use", tag)
}
return nil
}

Powered by TurnKey Linux.