mirror of
https://github.com/vlang/v.git
synced 2025-08-03 17:57:59 -04:00
168 lines
4.9 KiB
V
168 lines
4.9 KiB
V
// Copyright (c) 2022, 2024 blackshirt. All rights reserved.
|
|
// Use of this source code is governed by a MIT License
|
|
// that can be found in the LICENSE file.
|
|
module asn1
|
|
|
|
// default_boolean_tag is the default tag of ASN.1 BOOLEAN type.
|
|
pub const default_boolean_tag = Tag{.universal, false, int(TagType.boolean)}
|
|
|
|
// ASN.1 UNIVERSAL CLASS OF BOOLEAN TYPE.
|
|
//
|
|
// A Boolean value can take true or false.
|
|
// ASN.1 DER encoding restricts encoding of boolean true value into 0xff
|
|
// and otherwise, encodes into zero (0x00) for false value.
|
|
// The encoding of a boolean value shall be primitive. The contents octets shall consist of a single octet.
|
|
pub struct Boolean {
|
|
mut:
|
|
// boolean value represented in single byte to allow stores multiple value represents
|
|
// true value others than 0xff, ie., non-null byte representing true value.
|
|
value u8
|
|
}
|
|
|
|
// new creates a new Boolean value from true or false value.
|
|
// By default, when you pass true, its would store 0xff as underlying byte value.
|
|
// If you want more to be relaxed, see from_u8 to creates with another byte value.
|
|
pub fn Boolean.new(value bool) Boolean {
|
|
mut ret := Boolean{}
|
|
val := if value { u8(0xff) } else { u8(0x00) }
|
|
ret.value = val
|
|
|
|
return ret
|
|
}
|
|
|
|
// from_u8 creates a new Boolean value from single byte value.
|
|
fn Boolean.from_u8(value u8) Boolean {
|
|
return Boolean{
|
|
value: value
|
|
}
|
|
}
|
|
|
|
// tag returns the tag of Boolean type.
|
|
pub fn (v Boolean) tag() Tag {
|
|
return default_boolean_tag
|
|
}
|
|
|
|
fn (v Boolean) str() string {
|
|
res := if v.value() { 'Boolean (TRUE)' } else { 'Boolean (FALSE)' }
|
|
return res
|
|
}
|
|
|
|
// payload returns the payload of Boolean type in .der rule.
|
|
pub fn (b Boolean) payload() ![]u8 {
|
|
return b.payload_with_rule(.der)!
|
|
}
|
|
|
|
fn (b Boolean) payload_with_rule(rule EncodingRule) ![]u8 {
|
|
// by default, true value is encoded to 0xff
|
|
if rule == .der {
|
|
if b.value != u8(0xff) && b.value != u8(0x00) {
|
|
return error('Boolean: in .der, only 0xff or 0x00 are allowed')
|
|
}
|
|
}
|
|
return [b.value]
|
|
}
|
|
|
|
// parse tries to read a Boolean type from parser or return error on fails
|
|
pub fn Boolean.parse(mut p Parser) !Boolean {
|
|
tag := p.read_tag()!
|
|
if !tag.equal(default_boolean_tag) {
|
|
return error('Get unexpected non boolean tag')
|
|
}
|
|
length := p.read_length()!
|
|
if length != 1 {
|
|
return error('Bad boolean length')
|
|
}
|
|
bytes := p.read_bytes(length)!
|
|
value := Boolean.from_bytes(bytes)!
|
|
|
|
return value
|
|
}
|
|
|
|
// from_bytes creates a new ASN.1 BOOLEAN type from bytes b.
|
|
// Boolean type should fit in one byte length, otherwise it would return error.
|
|
// by default, p.rule == .der to follow DER restriction
|
|
fn Boolean.from_bytes(bytes []u8) !Boolean {
|
|
return Boolean.from_bytes_with_rule(bytes, .der)
|
|
}
|
|
|
|
fn Boolean.from_bytes_with_rule(bytes []u8, rule EncodingRule) !Boolean {
|
|
if bytes.len != 1 {
|
|
return error('Boolean: bad bytes')
|
|
}
|
|
// for DER requirements that "If the encoding represents the boolean value TRUE,
|
|
// its single contents octet shall have all eight bits set to one."
|
|
// Thus only 0 and 255 are valid encoded values.
|
|
// But, we relaxed this requirement to allow other than non-null
|
|
// value to be treated as TRUE value, like in BER encoding.
|
|
match bytes[0] {
|
|
u8(0x00) {
|
|
return Boolean.from_u8(0x00)
|
|
}
|
|
u8(0xff) {
|
|
return Boolean.from_u8(0xff)
|
|
}
|
|
else {
|
|
// other non-null value is treated as TRUE boolean value
|
|
if rule == .der {
|
|
return error('Boolean: in DER, other than 0xff is not allowed for true value')
|
|
}
|
|
return Boolean.from_u8(bytes[0])
|
|
}
|
|
}
|
|
}
|
|
|
|
// value gets the boolean value represented by underlying byte value.
|
|
// It returns FALSE if the byte == 0x00 and TRUE otherwise.
|
|
pub fn (b Boolean) value() bool {
|
|
return b.value_with_rule(.der)
|
|
}
|
|
|
|
fn (b Boolean) value_with_rule(rule EncodingRule) bool {
|
|
match b.value {
|
|
u8(0xff) {
|
|
return true
|
|
}
|
|
u8(0x00) {
|
|
return false
|
|
}
|
|
else {
|
|
if rule == .der {
|
|
return false
|
|
}
|
|
// otherwise non-null is considered as true
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
|
|
// decode tries to decode bytes array into Booelan type or error on fails.
|
|
fn Boolean.decode(src []u8) !(Boolean, int) {
|
|
return Boolean.decode_with_rule(src, 0, .der)!
|
|
}
|
|
|
|
fn Boolean.decode_with_rule(src []u8, loc int, rule EncodingRule) !(Boolean, int) {
|
|
if src.len < 3 {
|
|
return error('Boolean: bad length bytes')
|
|
}
|
|
if rule != .der && rule != .ber {
|
|
return error('Boolean: not supported rule')
|
|
}
|
|
tag, length_pos := Tag.decode_with_rule(src, loc, rule)!
|
|
if !tag.equal(default_boolean_tag) {
|
|
return error('Unexpected non-boolean tag')
|
|
}
|
|
length, content_pos := Length.decode_with_rule(src, length_pos, rule)!
|
|
if length != 1 {
|
|
return error('Boolean: should have length 1')
|
|
}
|
|
if content_pos >= src.len || content_pos + length > src.len {
|
|
return error('Boolean: truncated payload bytes')
|
|
}
|
|
payload := unsafe { src[content_pos..content_pos + length] }
|
|
|
|
// boolean value should be encoded in single byte
|
|
res := Boolean.from_bytes_with_rule(payload, rule)!
|
|
next := content_pos + length
|
|
return res, next
|
|
}
|