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

284 lines
8.1 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, BIT STRING, UTCTime and GeneralizedTime,
// 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"
"strings"
"time"
)
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). Equal
// elements may repeat, side by side: X.690 does not forbid it, and a time-
// stamping authority may send its certificate twice. Whoever counts the
// elements of a SET OF decides what a repetition means.
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
}
// ParseTime reads a UTCTime or a GeneralizedTime element as DER writes them
// (X.690 11.7 and 11.8): YYMMDDHHMMSSZ, with the years 50 to 99 in the 20th
// century (RFC 5280 4.1.2.5.1), or YYYYMMDDHHMMSS, an optional fraction of
// seconds without a trailing zero, and Z. A date or a time that does not
// exist, a second 60 included, is refused. fraction reports whether a
// GeneralizedTime has one.
func ParseTime(b []byte) (t time.Time, fraction bool, err error) {
if len(b) < 2 || (b[0] != 0x17 && b[0] != 0x18) {
return time.Time{}, false, errors.New("der: not a UTCTime or a GeneralizedTime")
}
c, err := Content(b)
if err != nil {
return time.Time{}, false, err
}
return parseTime(b[0], string(c))
}
func parseTime(tag byte, s string) (time.Time, bool, error) {
bad := errors.New("der: a time that is not in the form of DER")
if len(s) < 13 || s[len(s)-1] != 'Z' {
return time.Time{}, false, bad
}
body, frac := s[:len(s)-1], ""
var year int
switch tag {
case 0x17:
if len(body) != 12 || !digits(body) {
return time.Time{}, false, bad
}
year = atoi(body[:2]) + 1900
if year < 1950 {
year += 100
}
body = body[2:]
default:
if dot := strings.IndexByte(body, '.'); dot >= 0 {
body, frac = body[:dot], body[dot+1:]
if frac == "" || frac[len(frac)-1] == '0' || !digits(frac) {
return time.Time{}, false, bad
}
}
if len(body) != 14 || !digits(body) {
return time.Time{}, false, bad
}
year = atoi(body[:4])
body = body[4:]
}
month, day, hour, minute, second := atoi(body[0:2]), atoi(body[2:4]), atoi(body[4:6]), atoi(body[6:8]), atoi(body[8:10])
if month < 1 || month > 12 || day < 1 || hour > 23 || minute > 59 || second > 59 ||
day > time.Date(year, time.Month(month)+1, 0, 0, 0, 0, 0, time.UTC).Day() {
return time.Time{}, false, errors.New("der: a date or a time that does not exist")
}
nanos := 0
for i := 0; i < 9; i++ {
nanos *= 10
if i < len(frac) {
nanos += int(frac[i] - '0')
}
}
return time.Date(year, time.Month(month), day, hour, minute, second, nanos, time.UTC), frac != "", nil
}
func digits(s string) bool {
for i := 0; i < len(s); i++ {
if s[i] < '0' || s[i] > '9' {
return false
}
}
return s != ""
}
func atoi(s string) int {
n := 0
for i := 0; i < len(s); i++ {
n = n*10 + int(s[i]-'0')
}
return n
}
// 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 23, 24: // UTCTime, GeneralizedTime
if _, _, err := parseTime(tag, string(c)); err != nil {
return err
}
case 4, 12, 19, 20, 22, 26, 28, 30: // OCTET STRING and the string 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.