package asn1
import (
)
var (
byte00Encoder encoder = byteEncoder(0x00)
byteFFEncoder encoder = byteEncoder(0xff)
)
type encoder interface {
Len() int
Encode(dst []byte)
}
type byteEncoder byte
func ( byteEncoder) () int {
return 1
}
func ( byteEncoder) ( []byte) {
[0] = byte()
}
type bytesEncoder []byte
func ( bytesEncoder) () int {
return len()
}
func ( bytesEncoder) ( []byte) {
if copy(, ) != len() {
panic("internal error")
}
}
type stringEncoder string
func ( stringEncoder) () int {
return len()
}
func ( stringEncoder) ( []byte) {
if copy(, ) != len() {
panic("internal error")
}
}
type multiEncoder []encoder
func ( multiEncoder) () int {
var int
for , := range {
+= .Len()
}
return
}
func ( multiEncoder) ( []byte) {
var int
for , := range {
.Encode([:])
+= .Len()
}
}
type setEncoder []encoder
func ( setEncoder) () int {
var int
for , := range {
+= .Len()
}
return
}
func ( setEncoder) ( []byte) {
:= make([][]byte, len())
for , := range {
[] = make([]byte, .Len())
.Encode([])
}
sort.Slice(, func(, int) bool {
return bytes.Compare([], []) < 0
})
var int
for , := range {
copy([:], )
+= len()
}
}
type taggedEncoder struct {
scratch [8]byte
tag encoder
body encoder
}
func ( *taggedEncoder) () int {
return .tag.Len() + .body.Len()
}
func ( *taggedEncoder) ( []byte) {
.tag.Encode()
.body.Encode([.tag.Len():])
}
type int64Encoder int64
func ( int64Encoder) () int {
:= 1
for > 127 {
++
>>= 8
}
for < -128 {
++
>>= 8
}
return
}
func ( int64Encoder) ( []byte) {
:= .Len()
for := 0; < ; ++ {
[] = byte( >> uint((-1-)*8))
}
}
func ( int64) int {
if == 0 {
return 1
}
:= 0
for := ; > 0; >>= 7 {
++
}
return
}
func ( []byte, int64) []byte {
:= base128IntLength()
for := - 1; >= 0; -- {
:= byte( >> uint(*7))
&= 0x7f
if != 0 {
|= 0x80
}
= append(, )
}
return
}
func ( *big.Int) (encoder, error) {
if == nil {
return nil, StructuralError{"empty integer"}
}
if .Sign() < 0 {
:= new(big.Int).Neg()
.Sub(, bigOne)
:= .Bytes()
for := range {
[] ^= 0xff
}
if len() == 0 || [0]&0x80 == 0 {
return multiEncoder([]encoder{byteFFEncoder, bytesEncoder()}), nil
}
return bytesEncoder(), nil
} else if .Sign() == 0 {
return byte00Encoder, nil
} else {
:= .Bytes()
if len() > 0 && [0]&0x80 != 0 {
return multiEncoder([]encoder{byte00Encoder, bytesEncoder()}), nil
}
return bytesEncoder(), nil
}
}
func ( []byte, int) []byte {
:= lengthLength()
for ; > 0; -- {
= append(, byte(>>uint((-1)*8)))
}
return
}
func ( int) ( int) {
= 1
for > 255 {
++
>>= 8
}
return
}
func ( []byte, tagAndLength) []byte {
:= uint8(.class) << 6
if .isCompound {
|= 0x20
}
if .tag >= 31 {
|= 0x1f
= append(, )
= appendBase128Int(, int64(.tag))
} else {
|= uint8(.tag)
= append(, )
}
if .length >= 128 {
:= lengthLength(.length)
= append(, 0x80|byte())
= appendLength(, .length)
} else {
= append(, byte(.length))
}
return
}
type bitStringEncoder BitString
func ( bitStringEncoder) () int {
return len(.Bytes) + 1
}
func ( bitStringEncoder) ( []byte) {
[0] = byte((8 - .BitLength%8) % 8)
if copy([1:], .Bytes) != len(.Bytes) {
panic("internal error")
}
}
type oidEncoder []int
func ( oidEncoder) () int {
:= base128IntLength(int64([0]*40 + [1]))
for := 2; < len(); ++ {
+= base128IntLength(int64([]))
}
return
}
func ( oidEncoder) ( []byte) {
= appendBase128Int([:0], int64([0]*40+[1]))
for := 2; < len(); ++ {
= appendBase128Int(, int64([]))
}
}
func ( []int) ( encoder, error) {
if len() < 2 || [0] > 2 || ([0] < 2 && [1] >= 40) {
return nil, StructuralError{"invalid object identifier"}
}
return oidEncoder(), nil
}
func ( string) ( encoder, error) {
for := 0; < len(); ++ {
if !isPrintable([], allowAsterisk, rejectAmpersand) {
return nil, StructuralError{"PrintableString contains invalid character"}
}
}
return stringEncoder(), nil
}
func ( string) ( encoder, error) {
for := 0; < len(); ++ {
if [] > 127 {
return nil, StructuralError{"IA5String contains invalid character"}
}
}
return stringEncoder(), nil
}
func ( string) ( encoder, error) {
for := 0; < len(); ++ {
if !isNumeric([]) {
return nil, StructuralError{"NumericString contains invalid character"}
}
}
return stringEncoder(), nil
}
func ( string) encoder {
return stringEncoder()
}
func ( []byte, int) []byte {
return append(, byte('0'+(/10)%10), byte('0'+%10))
}
func ( []byte, int) []byte {
var [4]byte
for := range {
[3-] = '0' + byte(%10)
/= 10
}
return append(, [:]...)
}
func ( time.Time) bool {
:= .Year()
return < 1950 || >= 2050
}
func ( time.Time) ( encoder, error) {
:= make([]byte, 0, 18)
, = appendUTCTime(, )
if != nil {
return nil,
}
return bytesEncoder(), nil
}
func ( time.Time) ( encoder, error) {
:= make([]byte, 0, 20)
, = appendGeneralizedTime(, )
if != nil {
return nil,
}
return bytesEncoder(), nil
}
func ( []byte, time.Time) ( []byte, error) {
:= .Year()
switch {
case 1950 <= && < 2000:
= appendTwoDigits(, -1900)
case 2000 <= && < 2050:
= appendTwoDigits(, -2000)
default:
return nil, StructuralError{"cannot represent time as UTCTime"}
}
return appendTimeCommon(, ), nil
}
func ( []byte, time.Time) ( []byte, error) {
:= .Year()
if < 0 || > 9999 {
return nil, StructuralError{"cannot represent time as GeneralizedTime"}
}
= appendFourDigits(, )
return appendTimeCommon(, ), nil
}
func ( []byte, time.Time) []byte {
, , := .Date()
= appendTwoDigits(, int())
= appendTwoDigits(, )
, , := .Clock()
= appendTwoDigits(, )
= appendTwoDigits(, )
= appendTwoDigits(, )
, := .Zone()
switch {
case /60 == 0:
return append(, 'Z')
case > 0:
= append(, '+')
case < 0:
= append(, '-')
}
:= / 60
if < 0 {
= -
}
= appendTwoDigits(, /60)
= appendTwoDigits(, %60)
return
}
func ( []byte) []byte {
, , := parseTagAndLength(, 0)
if != nil {
return
}
return [:]
}
func ( reflect.Value, fieldParameters) ( encoder, error) {
switch .Type() {
case flagType:
return bytesEncoder(nil), nil
case timeType:
:= .Interface().(time.Time)
if .timeType == TagGeneralizedTime || outsideUTCRange() {
return makeGeneralizedTime()
}
return makeUTCTime()
case bitStringType:
return bitStringEncoder(.Interface().(BitString)), nil
case objectIdentifierType:
return makeObjectIdentifier(.Interface().(ObjectIdentifier))
case bigIntType:
return makeBigInt(.Interface().(*big.Int))
}
switch := ; .Kind() {
case reflect.Bool:
if .Bool() {
return byteFFEncoder, nil
}
return byte00Encoder, nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return int64Encoder(.Int()), nil
case reflect.Struct:
:= .Type()
for := 0; < .NumField(); ++ {
if .Field().PkgPath != "" {
return nil, StructuralError{"struct contains unexported fields"}
}
}
:= 0
:= .NumField()
if == 0 {
return bytesEncoder(nil), nil
}
if .Field(0).Type == rawContentsType {
:= .Field(0)
if .Len() > 0 {
:= .Bytes()
return bytesEncoder(stripTagAndLength()), nil
}
= 1
}
switch := - ; {
case 0:
return bytesEncoder(nil), nil
case 1:
return makeField(.Field(), parseFieldParameters(.Field().Tag.Get("asn1")))
default:
:= make([]encoder, )
for := 0; < ; ++ {
[], = makeField(.Field(+), parseFieldParameters(.Field(+).Tag.Get("asn1")))
if != nil {
return nil,
}
}
return multiEncoder(), nil
}
case reflect.Slice:
:= .Type()
if .Elem().Kind() == reflect.Uint8 {
return bytesEncoder(.Bytes()), nil
}
var fieldParameters
switch := .Len(); {
case 0:
return bytesEncoder(nil), nil
case 1:
return makeField(.Index(0), )
default:
:= make([]encoder, )
for := 0; < ; ++ {
[], = makeField(.Index(), )
if != nil {
return nil,
}
}
if .set {
return setEncoder(), nil
}
return multiEncoder(), nil
}
case reflect.String:
switch .stringType {
case TagIA5String:
return makeIA5String(.String())
case TagPrintableString:
return makePrintableString(.String())
case TagNumericString:
return makeNumericString(.String())
default:
return makeUTF8String(.String()), nil
}
}
return nil, StructuralError{"unknown Go type"}
}
func ( reflect.Value, fieldParameters) ( encoder, error) {
if !.IsValid() {
return nil, fmt.Errorf("asn1: cannot marshal nil value")
}
if .Kind() == reflect.Interface && .Type().NumMethod() == 0 {
return (.Elem(), )
}
if .Kind() == reflect.Slice && .Len() == 0 && .omitEmpty {
return bytesEncoder(nil), nil
}
if .optional && .defaultValue != nil && canHaveDefaultValue(.Kind()) {
:= reflect.New(.Type()).Elem()
.SetInt(*.defaultValue)
if reflect.DeepEqual(.Interface(), .Interface()) {
return bytesEncoder(nil), nil
}
}
if .optional && .defaultValue == nil {
if reflect.DeepEqual(.Interface(), reflect.Zero(.Type()).Interface()) {
return bytesEncoder(nil), nil
}
}
if .Type() == rawValueType {
:= .Interface().(RawValue)
if len(.FullBytes) != 0 {
return bytesEncoder(.FullBytes), nil
}
:= new(taggedEncoder)
.tag = bytesEncoder(appendTagAndLength(.scratch[:0], tagAndLength{.Class, .Tag, len(.Bytes), .IsCompound}))
.body = bytesEncoder(.Bytes)
return , nil
}
, , , := getUniversalType(.Type())
if ! || {
return nil, StructuralError{fmt.Sprintf("unknown Go type: %v", .Type())}
}
if .timeType != 0 && != TagUTCTime {
return nil, StructuralError{"explicit time type given to non-time member"}
}
if .stringType != 0 && != TagPrintableString {
return nil, StructuralError{"explicit string type given to non-string member"}
}
switch {
case TagPrintableString:
if .stringType == 0 {
for , := range .String() {
if >= utf8.RuneSelf || !isPrintable(byte(), rejectAsterisk, rejectAmpersand) {
if !utf8.ValidString(.String()) {
return nil, errors.New("asn1: string not valid UTF-8")
}
= TagUTF8String
break
}
}
} else {
= .stringType
}
case TagUTCTime:
if .timeType == TagGeneralizedTime || outsideUTCRange(.Interface().(time.Time)) {
= TagGeneralizedTime
}
}
if .set {
if != TagSequence {
return nil, StructuralError{"non sequence tagged as set"}
}
= TagSet
}
if == TagSet && !.set {
.set = true
}
:= new(taggedEncoder)
.body, = makeBody(, )
if != nil {
return nil,
}
:= .body.Len()
:= ClassUniversal
if .tag != nil {
if .application {
= ClassApplication
} else if .private {
= ClassPrivate
} else {
= ClassContextSpecific
}
if .explicit {
.tag = bytesEncoder(appendTagAndLength(.scratch[:0], tagAndLength{ClassUniversal, , , }))
:= new(taggedEncoder)
.body =
.tag = bytesEncoder(appendTagAndLength(.scratch[:0], tagAndLength{
class: ,
tag: *.tag,
length: + .tag.Len(),
isCompound: true,
}))
return , nil
}
= *.tag
}
.tag = bytesEncoder(appendTagAndLength(.scratch[:0], tagAndLength{, , , }))
return , nil
}
func ( interface{}) ([]byte, error) {
return MarshalWithParams(, "")
}
func ( interface{}, string) ([]byte, error) {
, := makeField(reflect.ValueOf(), parseFieldParameters())
if != nil {
return nil,
}
:= make([]byte, .Len())
.Encode()
return , nil
}