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.
133 lines
4.8 KiB
133 lines
4.8 KiB
package der
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestCheck(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name, hex string
|
|
ok bool
|
|
}{
|
|
{"sequence of an integer and a null", "3005020101" + "0500", true},
|
|
{"a long length", "04" + "8180" + zeros(128), true},
|
|
{"a long form under 128", "0481" + "01" + "00", false},
|
|
{"a length with a leading zero", "04820001" + "00", false},
|
|
{"a length of 128 with a leading zero", "04820080" + zeros(128), false},
|
|
{"an indefinite length", "30800000", false},
|
|
{"a high tag number", "1f0100", false},
|
|
{"truncated", "0402aa", false},
|
|
{"trailing bytes", "0500" + "00", false},
|
|
{"BOOLEAN 01", "010101", false},
|
|
{"BOOLEAN FF", "0101ff", true},
|
|
{"INTEGER with a leading zero", "02020001", false},
|
|
{"INTEGER 0x80 with its zero", "02020080", true},
|
|
{"INTEGER with a leading FF", "0202ff80", false},
|
|
{"empty INTEGER", "0200", false},
|
|
{"NULL with content", "050100", false},
|
|
{"constructed OCTET STRING", "2404" + "0402aabb", false},
|
|
{"BIT STRING with unused bits set", "03020701", false},
|
|
{"BIT STRING with unused bits clear", "03020780", true},
|
|
{"BIT STRING of 4 bits", "030204f0", true},
|
|
{"OID", "06032a0304", true},
|
|
{"OID with a leading 0x80", "06038001" + "02", false},
|
|
{"OID that does not end", "06022a83", false},
|
|
{"context tag, constructed", "a003020101", true},
|
|
{"SET in primitive form", "1100", false},
|
|
{"the end of contents", "0000", false},
|
|
{"a reserved universal tag", "0e0141", false},
|
|
{"a SEQUENCE of the end of contents", "30020000", false},
|
|
{"UTF8String", "0c026162", true},
|
|
// Times in the forms of DER (X.690 11.7, 11.8).
|
|
{"UTCTime", "170d" + hex.EncodeToString([]byte("250101120000Z")), true},
|
|
{"UTCTime without seconds", "170b" + hex.EncodeToString([]byte("2501011200Z")), false},
|
|
{"UTCTime with an offset", "1711" + hex.EncodeToString([]byte("250101120000+0100")), false},
|
|
{"UTCTime of 30 February", "170d" + hex.EncodeToString([]byte("250230120000Z")), false},
|
|
{"UTCTime with second 60", "170d" + hex.EncodeToString([]byte("250101235960Z")), false},
|
|
{"a UTCTime that is not a time", "170a" + hex.EncodeToString([]byte("not a time")), false},
|
|
{"GeneralizedTime", "180f" + hex.EncodeToString([]byte("20250101120000Z")), true},
|
|
{"GeneralizedTime with a fraction", "1812" + hex.EncodeToString([]byte("20250101120000.25Z")), true},
|
|
{"GeneralizedTime with a trailing zero", "1813" + hex.EncodeToString([]byte("20250101120000.250Z")), false},
|
|
{"GeneralizedTime with an empty fraction", "1810" + hex.EncodeToString([]byte("20250101120000.Z")), false},
|
|
{"GeneralizedTime without Z", "180e" + hex.EncodeToString([]byte("20250101120000")), false},
|
|
{"GeneralizedTime with a comma", "1812" + hex.EncodeToString([]byte("20250101120000,25Z")), false},
|
|
} {
|
|
b, err := hex.DecodeString(tc.hex)
|
|
if err != nil {
|
|
t.Fatal(tc.name, err)
|
|
}
|
|
if err := Check(b); (err == nil) != tc.ok {
|
|
t.Errorf("%s: %v", tc.name, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func zeros(n int) string {
|
|
b := make([]byte, n*2)
|
|
for i := range b {
|
|
b[i] = '0'
|
|
}
|
|
return string(b)
|
|
}
|
|
|
|
// The elements of a SET OF go in ascending order, and equal ones may repeat
|
|
// (X.690 11.6).
|
|
func TestSetOfSorted(t *testing.T) {
|
|
a, b := []byte{0x02, 0x01, 0x01}, []byte{0x02, 0x01, 0x02}
|
|
if !SetOfSorted([][]byte{a, b}) || SetOfSorted([][]byte{b, a}) || !SetOfSorted([][]byte{a, a, b}) || SetOfSorted([][]byte{a, b, a}) {
|
|
t.Error("SetOfSorted")
|
|
}
|
|
}
|
|
|
|
// Elements nested 32 levels below the outer one are DER; one more is too deep.
|
|
func TestDepth(t *testing.T) {
|
|
nested := func(n int) []byte {
|
|
b := []byte{0x05, 0x00}
|
|
for range n {
|
|
b = append([]byte{0x30, byte(len(b))}, b...)
|
|
}
|
|
return b
|
|
}
|
|
if err := Check(nested(maxDepth)); err != nil {
|
|
t.Errorf("%d levels: %v", maxDepth, err)
|
|
}
|
|
if err := Check(nested(maxDepth + 1)); err == nil {
|
|
t.Errorf("%d levels: accepted", maxDepth+1)
|
|
}
|
|
}
|
|
|
|
func TestParseTime(t *testing.T) {
|
|
for _, c := range []struct {
|
|
el string
|
|
want time.Time
|
|
frac bool
|
|
}{
|
|
{"\x17\x0d" + "491231235959Z", time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC), false},
|
|
{"\x17\x0d" + "500101000000Z", time.Date(1950, 1, 1, 0, 0, 0, 0, time.UTC), false},
|
|
{"\x18\x13" + "20240229120000.125Z", time.Date(2024, 2, 29, 12, 0, 0, 125e6, time.UTC), true},
|
|
} {
|
|
got, frac, err := ParseTime([]byte(c.el))
|
|
if err != nil || !got.Equal(c.want) || frac != c.frac {
|
|
t.Errorf("%q: %v %v %v", c.el, got, frac, err)
|
|
}
|
|
}
|
|
for _, bad := range []string{"\x18\x0f" + "20230229120000Z", "\x04\x0d" + "491231235959Z", "\x17"} {
|
|
if _, _, err := ParseTime([]byte(bad)); err == nil {
|
|
t.Errorf("%q: accepted", bad)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSplit(t *testing.T) {
|
|
b, _ := hex.DecodeString("30050201010500")
|
|
if err := Check(b); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
id, kids, err := Split(b)
|
|
if err != nil || id != 0x30 || len(kids) != 2 || len(kids[0]) != 3 || len(kids[1]) != 2 {
|
|
t.Errorf("%x %v %v", id, kids, err)
|
|
}
|
|
}
|