// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package asn1

import (
	
	
	
	
	
	
	
	
)

var (
	byte00Encoder encoder = byteEncoder(0x00)
	byteFFEncoder encoder = byteEncoder(0xff)
)

// encoder represents an ASN.1 element that is waiting to be marshaled.
type encoder interface {
	// Len returns the number of bytes needed to marshal this element.
	Len() int
	// Encode encodes this element by writing Len() bytes to dst.
	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) {
	// Per X690 Section 11.6: The encodings of the component values of a
	// set-of value shall appear in ascending order, the encodings being
	// compared as octet strings with the shorter components being padded
	// at their trailing end with 0-octets.
	//
	// First we encode each element to its TLV encoding and then use
	// octetSort to get the ordering expected by X690 DER rules before
	// writing the sorted encodings out to dst.
	 := make([][]byte, len())
	for ,  := range  {
		[] = make([]byte, .Len())
		.Encode([])
	}

	// Since we are using bytes.Compare to compare TLV encodings we
	// don't need to right pad s[i] and s[j] to the same length as
	// suggested in X690. If len(s[i]) < len(s[j]) the length octet of
	// s[i], which is the first determining byte, will inherently be
	// smaller than the length octet of s[j]. This lets us skip the
	// padding step.
	slices.SortFunc(, bytes.Compare)

	var  int
	for ,  := range  {
		copy([:], )
		 += len()
	}
}

type taggedEncoder struct {
	// scratch contains temporary space for encoding the tag and length of
	// an element in order to avoid extra allocations.
	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 base128IntLength( int64) int {
	if  == 0 {
		return 1
	}

	 := 0
	for  := ;  > 0;  >>= 7 {
		++
	}

	return 
}

func appendBase128Int( []byte,  int64) []byte {
	 := base128IntLength()

	for  :=  - 1;  >= 0; -- {
		 := byte( >> uint(*7))
		 &= 0x7f
		if  != 0 {
			 |= 0x80
		}

		 = append(, )
	}

	return 
}

func makeBigInt( *big.Int) (encoder, error) {
	if  == nil {
		return nil, StructuralError{"empty integer"}
	}

	if .Sign() < 0 {
		// A negative number has to be converted to two's-complement
		// form. So we'll invert and subtract 1. If the
		// most-significant-bit isn't set then we'll need to pad the
		// beginning with 0xff in order to keep the number negative.
		 := 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 {
		// Zero is written as a single 0 zero rather than no bytes.
		return byte00Encoder, nil
	} else {
		 := .Bytes()
		if len() > 0 && [0]&0x80 != 0 {
			// We'll have to pad this with 0x00 in order to stop it
			// looking like a negative number.
			return multiEncoder([]encoder{byte00Encoder, bytesEncoder()}), nil
		}
		return bytesEncoder(), nil
	}
}

func appendLength( []byte,  int) []byte {
	 := lengthLength()

	for ;  > 0; -- {
		 = append(, byte(>>uint((-1)*8)))
	}

	return 
}

func lengthLength( int) ( int) {
	 = 1
	for  > 255 {
		++
		 >>= 8
	}
	return
}

func appendTagAndLength( []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 makeObjectIdentifier( []int) ( encoder,  error) {
	if len() < 2 || [0] > 2 || ([0] < 2 && [1] >= 40) {
		return nil, StructuralError{"invalid object identifier"}
	}

	return oidEncoder(), nil
}

func makePrintableString( string) ( encoder,  error) {
	for  := 0;  < len(); ++ {
		// The asterisk is often used in PrintableString, even though
		// it is invalid. If a PrintableString was specifically
		// requested then the asterisk is permitted by this code.
		// Ampersand is allowed in parsing due a handful of CA
		// certificates, however when making new certificates
		// it is rejected.
		if !isPrintable([], allowAsterisk, rejectAmpersand) {
			return nil, StructuralError{"PrintableString contains invalid character"}
		}
	}

	return stringEncoder(), nil
}

func makeIA5String( string) ( encoder,  error) {
	for  := 0;  < len(); ++ {
		if [] > 127 {
			return nil, StructuralError{"IA5String contains invalid character"}
		}
	}

	return stringEncoder(), nil
}

func makeNumericString( string) ( encoder,  error) {
	for  := 0;  < len(); ++ {
		if !isNumeric([]) {
			return nil, StructuralError{"NumericString contains invalid character"}
		}
	}

	return stringEncoder(), nil
}

func makeUTF8String( string) encoder {
	return stringEncoder()
}

func appendTwoDigits( []byte,  int) []byte {
	return append(, byte('0'+(/10)%10), byte('0'+%10))
}

func appendFourDigits( []byte,  int) []byte {
	return append(,
		byte('0'+(/1000)%10),
		byte('0'+(/100)%10),
		byte('0'+(/10)%10),
		byte('0'+%10))
}

func outsideUTCRange( time.Time) bool {
	 := .Year()
	return  < 1950 ||  >= 2050
}

func makeUTCTime( time.Time) ( encoder,  error) {
	 := make([]byte, 0, 18)

	,  = appendUTCTime(, )
	if  != nil {
		return nil, 
	}

	return bytesEncoder(), nil
}

func makeGeneralizedTime( time.Time) ( encoder,  error) {
	 := make([]byte, 0, 20)

	,  = appendGeneralizedTime(, )
	if  != nil {
		return nil, 
	}

	return bytesEncoder(), nil
}

func appendUTCTime( []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 appendGeneralizedTime( []byte,  time.Time) ( []byte,  error) {
	 := .Year()
	if  < 0 ||  > 9999 {
		return nil, StructuralError{"cannot represent time as GeneralizedTime"}
	}

	 = appendFourDigits(, )

	return appendTimeCommon(, ), nil
}

func appendTimeCommon( []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 stripTagAndLength( []byte) []byte {
	, ,  := parseTagAndLength(, 0)
	if  != nil {
		return 
	}
	return [:]
}

func makeBody( 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().IsExported() {
				return nil, StructuralError{"struct contains unexported fields"}
			}
		}

		 := 0

		 := .NumField()
		if  == 0 {
			return bytesEncoder(nil), nil
		}

		// If the first element of the structure is a non-empty
		// RawContents, then we don't bother serializing the rest.
		if .Field(0).Type == rawContentsType {
			 := .Field(0)
			if .Len() > 0 {
				 := .Bytes()
				/* The RawContents will contain the tag and
				 * length fields but we'll also be writing
				 * those ourselves, so we strip them out of
				 * 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 makeField( reflect.Value,  fieldParameters) ( encoder,  error) {
	if !.IsValid() {
		return nil, fmt.Errorf("asn1: cannot marshal nil value")
	}
	// If the field is an interface{} then recurse into it.
	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 no default value is given then the zero value for the type is
	// assumed to be the default value. This isn't obviously the correct
	// behavior, but it's what Go has traditionally done.
	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 {
			// This is a string without an explicit string type. We'll use
			// a PrintableString if the character set in the string is
			// sufficiently limited, otherwise we'll use a UTF8String.
			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
	}

	// makeField can be called for a slice that should be treated as a SET
	// but doesn't have params.set set, for instance when using a slice
	// with the SET type name suffix. In this case getUniversalType returns
	// TagSet, but makeBody doesn't know about that so will treat the slice
	// as a sequence. To work around this we set params.set.
	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
		}

		// implicit tag.
		 = *.tag
	}

	.tag = bytesEncoder(appendTagAndLength(.scratch[:0], tagAndLength{, , , }))

	return , nil
}

// Marshal returns the ASN.1 encoding of val.
//
// In addition to the struct tags recognized by Unmarshal, the following can be
// used:
//
//	ia5:         causes strings to be marshaled as ASN.1, IA5String values
//	omitempty:   causes empty slices to be skipped
//	printable:   causes strings to be marshaled as ASN.1, PrintableString values
//	utf8:        causes strings to be marshaled as ASN.1, UTF8String values
//	utc:         causes time.Time to be marshaled as ASN.1, UTCTime values
//	generalized: causes time.Time to be marshaled as ASN.1, GeneralizedTime values
func ( any) ([]byte, error) {
	return MarshalWithParams(, "")
}

// MarshalWithParams allows field parameters to be specified for the
// top-level element. The form of the params is the same as the field tags.
func ( any,  string) ([]byte, error) {
	,  := makeField(reflect.ValueOf(), parseFieldParameters())
	if  != nil {
		return nil, 
	}
	 := make([]byte, .Len())
	.Encode()
	return , nil
}