github.com/egonelbre/exp@v0.0.0-20240430123955-ed1d3aa93911/smime/ber/value.go (about)

     1  package ber
     2  
     3  import (
     4  	"encoding/asn1"
     5  	"fmt"
     6  	"math/big"
     7  	"time"
     8  )
     9  
    10  func (v *Token) mustBeValue() {
    11  	if v.Kind != Value {
    12  		panic(fmt.Sprintf("invalid call on non-kind: %#v", v))
    13  	}
    14  }
    15  
    16  func (v *Token) Universal() (ret interface{}, err error) {
    17  	v.mustBeValue()
    18  	if v.Class != Universal {
    19  		err = SyntaxError{"not an universal value"}
    20  		return
    21  	}
    22  
    23  	switch v.Tag {
    24  	case TagBool:
    25  		ret, err = v.AsBool()
    26  	case TagInteger:
    27  		ret, err = v.AsBigInt()
    28  	case TagBitString:
    29  		ret, err = v.AsBitString()
    30  	case TagOctetString:
    31  		ret, err = v.AsOctetString()
    32  	case TagNULL:
    33  		ret = struct{}{}
    34  	case TagObjectIdentifier:
    35  		ret, err = v.AsObjectIdentifier()
    36  	// case TagObjectDescriptor:
    37  	// case TagExternal:
    38  	// case TagRealFloat:
    39  	case TagEnumerated:
    40  		ret, err = v.AsInt64()
    41  	// case TagEmbeddedPDV:
    42  	case TagUTF8String:
    43  		ret, err = v.AsUTF8String()
    44  	// case TagRelativeOID:
    45  	// case TagSequence:
    46  	// case TagSet:
    47  	case TagNumericString:
    48  		ret, err = v.AsNumericString()
    49  	case TagPrintableString:
    50  		ret, err = v.AsPrintableString()
    51  	case TagT61String:
    52  		ret, err = v.AsT61String()
    53  	// case TagVideotexString:
    54  	case TagIA5String:
    55  		ret, err = v.AsIA5String()
    56  	case TagUTCTime:
    57  		ret, err = v.AsUTCTime()
    58  	case TagGeneralizedTime:
    59  		ret, err = v.AsGeneralizedTime()
    60  	//case TagGraphicString:
    61  	case TagVisibleString:
    62  		ret, err = v.AsVisibleString()
    63  	case TagGeneralString:
    64  		ret, err = v.AsUTF8String()
    65  	case TagUniversalString:
    66  		ret, err = v.AsUTF8String()
    67  	case TagCharacterString:
    68  		ret, err = v.AsUTF8String()
    69  	//case TagBMPString:
    70  	default:
    71  		err = unimplementedType
    72  	}
    73  
    74  	return
    75  }
    76  
    77  // BOOLEAN
    78  
    79  func (v *Token) AsBool() (ret bool, err error) {
    80  	v.mustBeValue()
    81  	bytes := v.Bytes
    82  	if len(bytes) != 1 {
    83  		err = SyntaxError{"invalid boolean"}
    84  		return
    85  	}
    86  
    87  	// DER demands that "If the encoding represents the boolean value TRUE,
    88  	// its single contents octet shall have all eight bits set to one."
    89  	// Thus only 0 and 255 are valid encoded values.
    90  	switch bytes[0] {
    91  	case 0:
    92  		ret = false
    93  	case 1:
    94  		ret = true
    95  	default:
    96  		err = SyntaxError{"invalid boolean"}
    97  	}
    98  	return
    99  }
   100  
   101  // INTEGER
   102  
   103  // AsInt64 treats the given bytes as a big-endian, signed integer and
   104  // returns the result.
   105  func (v *Token) AsInt64() (ret int64, err error) {
   106  	v.mustBeValue()
   107  	bytes := v.Bytes
   108  	if len(bytes) > 8 {
   109  		// We'll overflow an int64 in this case.
   110  		err = StructuralError{"integer too large"}
   111  		return
   112  	}
   113  	for bytesRead := 0; bytesRead < len(bytes); bytesRead++ {
   114  		ret <<= 8
   115  		ret |= int64(bytes[bytesRead])
   116  	}
   117  
   118  	// Shift up and down in order to sign extend the result.
   119  	ret <<= 64 - uint8(len(bytes))*8
   120  	ret >>= 64 - uint8(len(bytes))*8
   121  	return
   122  }
   123  
   124  // AsInt32 treats the given bytes as a big-endian, signed integer and returns
   125  // the result.
   126  func (v *Token) AsInt32() (ret int32, err error) {
   127  	v.mustBeValue()
   128  	ret64, err := v.AsInt64()
   129  	if err != nil {
   130  		return 0, err
   131  	}
   132  	if ret64 != int64(int32(ret64)) {
   133  		return 0, StructuralError{"integer too large"}
   134  	}
   135  	return int32(ret64), nil
   136  }
   137  
   138  var bigOne = big.NewInt(1)
   139  
   140  // parseBigInt treats the given bytes as a big-endian, signed integer and returns
   141  // the result.
   142  func (v *Token) AsBigInt() (*big.Int, error) {
   143  	v.mustBeValue()
   144  	bytes := v.Bytes
   145  	ret := new(big.Int)
   146  	if len(bytes) > 0 && bytes[0]&0x80 == 0x80 {
   147  		// This is a negative number.
   148  		notBytes := make([]byte, len(bytes))
   149  		for i := range notBytes {
   150  			notBytes[i] = ^bytes[i]
   151  		}
   152  		ret.SetBytes(notBytes)
   153  		ret.Add(ret, bigOne)
   154  		ret.Neg(ret)
   155  		return ret, nil
   156  	}
   157  	ret.SetBytes(bytes)
   158  	return ret, nil
   159  }
   160  
   161  // BIT STRING
   162  
   163  // AsBitString parses an ASN.1 bit string from the given byte slice and returns it.
   164  func (v *Token) AsBitString() (ret asn1.BitString, err error) {
   165  	v.mustBeValue()
   166  	bytes := v.Bytes
   167  	if len(bytes) == 0 {
   168  		err = SyntaxError{"zero length BIT STRING"}
   169  		return
   170  	}
   171  	paddingBits := int(bytes[0])
   172  	if paddingBits > 7 ||
   173  		len(bytes) == 1 && paddingBits > 0 {
   174  		err = SyntaxError{"invalid padding bits in BIT STRING"}
   175  		return
   176  	}
   177  	ret.BitLength = (len(bytes)-1)*8 - paddingBits
   178  	ret.Bytes = bytes[1:]
   179  
   180  	// remove the padding bits
   181  	last := len(ret.Bytes) - 1
   182  	ret.Bytes[last] = (ret.Bytes[last] >> uint(paddingBits)) << uint(paddingBits)
   183  	return
   184  }
   185  
   186  func (v *Token) AsOctetString() (ret []byte, err error) {
   187  	v.mustBeValue()
   188  	return v.Bytes, nil
   189  }
   190  
   191  // AsObjectIdentifier parses an OBJECT IDENTIFIER from the given bytes and
   192  // returns it. An object identifier is a sequence of variable length integers
   193  // that are assigned in a hierarchy.
   194  func (val *Token) AsObjectIdentifier() (s asn1.ObjectIdentifier, err error) {
   195  	val.mustBeValue()
   196  	bytes := val.Bytes
   197  	if len(bytes) == 0 {
   198  		err = SyntaxError{"zero length OBJECT IDENTIFIER"}
   199  		return
   200  	}
   201  
   202  	// In the worst case, we get two elements from the first byte (which is
   203  	// encoded differently) and then every varint is a single byte long.
   204  	s = make(asn1.ObjectIdentifier, len(bytes)+1)
   205  
   206  	// The first varint is 40*Token1 + value2:
   207  	// According to this packing, value1 can take the values 0, 1 and 2 only.
   208  	// When value1 = 0 or value1 = 1, then value2 is <= 39. When value1 = 2,
   209  	// then there are no restrictions on value2.
   210  	v, offset, err := parseBase128Int(bytes, 0)
   211  	if err != nil {
   212  		return
   213  	}
   214  	if v < 80 {
   215  		s[0] = v / 40
   216  		s[1] = v % 40
   217  	} else {
   218  		s[0] = 2
   219  		s[1] = v - 80
   220  	}
   221  
   222  	i := 2
   223  	for ; offset < len(bytes); i++ {
   224  		v, offset, err = parseBase128Int(bytes, offset)
   225  		if err != nil {
   226  			return
   227  		}
   228  		s[i] = v
   229  	}
   230  	s = s[0:i]
   231  	return
   232  }
   233  
   234  // UTCTime
   235  
   236  func (v *Token) AsUTCTime() (ret time.Time, err error) {
   237  	v.mustBeValue()
   238  	s := string(v.Bytes)
   239  	ret, err = time.Parse("0601021504Z0700", s)
   240  	if err != nil {
   241  		ret, err = time.Parse("060102150405Z0700", s)
   242  	}
   243  	if err == nil && ret.Year() >= 2050 {
   244  		// UTCTime only encodes times prior to 2050. See https://tools.ietf.org/html/rfc5280#section-4.1.2.5.1
   245  		ret = ret.AddDate(-100, 0, 0)
   246  	}
   247  
   248  	return
   249  }
   250  
   251  // AsGeneralizedTime parses the GeneralizedTime from the given byte slice
   252  // and returns the resulting time.
   253  func (v *Token) AsGeneralizedTime() (ret time.Time, err error) {
   254  	v.mustBeValue()
   255  	return time.Parse("20060102150405Z0700", string(v.Bytes))
   256  }
   257  
   258  // NumericString
   259  func (v *Token) AsNumericString() (ret string, err error) {
   260  	v.mustBeValue()
   261  	bytes := v.Bytes
   262  	for _, b := range bytes {
   263  		if !isNumeric(b) {
   264  			err = SyntaxError{"NumericString contains invalid character"}
   265  			return
   266  		}
   267  	}
   268  	ret = string(bytes)
   269  	return
   270  }
   271  
   272  // isNumeric returns true iff the given b is in the ASN.1 NumericString set.
   273  func isNumeric(b byte) bool {
   274  	return '0' <= b && b <= '9' || b == ' '
   275  }
   276  
   277  // AsPrintableString parses a ASN.1 PrintableString from the given byte
   278  // array and returns it.
   279  func (v *Token) AsPrintableString() (ret string, err error) {
   280  	v.mustBeValue()
   281  	bytes := v.Bytes
   282  	for _, b := range bytes {
   283  		if !isPrintable(b) {
   284  			err = SyntaxError{"PrintableString contains invalid character"}
   285  			return
   286  		}
   287  	}
   288  	ret = string(bytes)
   289  	return
   290  }
   291  
   292  // isPrintable returns true iff the given b is in the ASN.1 PrintableString set.
   293  func isPrintable(b byte) bool {
   294  	return 'a' <= b && b <= 'z' ||
   295  		'A' <= b && b <= 'Z' ||
   296  		'0' <= b && b <= '9' ||
   297  		'\'' <= b && b <= ')' ||
   298  		'+' <= b && b <= '/' ||
   299  		b == ' ' ||
   300  		b == ':' ||
   301  		b == '=' ||
   302  		b == '?' ||
   303  		// This is technically not allowed in a PrintableString.
   304  		// However, x509 certificates with wildcard strings don't
   305  		// always use the correct string type so we permit it.
   306  		b == '*'
   307  }
   308  
   309  // VisibleString
   310  
   311  // AsVisibleString parses a ASN.1 VisibleString from the given byte
   312  // array and returns it.
   313  func (v *Token) AsVisibleString() (ret string, err error) {
   314  	v.mustBeValue()
   315  	bytes := v.Bytes
   316  	for _, b := range bytes {
   317  		if b < 0x20 {
   318  			err = SyntaxError{"VisibleString contains invalid character"}
   319  			return
   320  		}
   321  	}
   322  	ret = string(bytes)
   323  	return
   324  }
   325  
   326  // IA5String
   327  
   328  // parseIA5String parses a ASN.1 IA5String (ASCII string) from the given
   329  // byte slice and returns it.
   330  func (v *Token) AsIA5String() (ret string, err error) {
   331  	v.mustBeValue()
   332  	bytes := v.Bytes
   333  	for _, b := range bytes {
   334  		if b >= 0x80 {
   335  			err = SyntaxError{"IA5String contains invalid character"}
   336  			return
   337  		}
   338  	}
   339  	ret = string(bytes)
   340  	return
   341  }
   342  
   343  // T61String
   344  
   345  // parseT61String parses a ASN.1 T61String (8-bit clean string) from the given
   346  // byte slice and returns it.
   347  func (v *Token) AsT61String() (ret string, err error) {
   348  	v.mustBeValue()
   349  	return string(v.Bytes), nil
   350  }
   351  
   352  // UTF8String
   353  
   354  // parseUTF8String parses a ASN.1 UTF8String (raw UTF-8) from the given byte
   355  // array and returns it.
   356  func (v *Token) AsUTF8String() (ret string, err error) {
   357  	v.mustBeValue()
   358  	return string(v.Bytes), nil
   359  }