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 }