From 58fc4dead559901cad648fb695f31d0f6de9945a Mon Sep 17 00:00:00 2001 From: blackshirt Date: Thu, 21 Nov 2024 18:05:00 +0700 Subject: [PATCH] x.encoding.asn1: clean up the source code of the module after the recent compiler changes and bugfixes (#22932) --- vlib/x/encoding/asn1/bitstring.v | 12 +- vlib/x/encoding/asn1/boolean.v | 6 +- vlib/x/encoding/asn1/boolean_test.v | 4 - vlib/x/encoding/asn1/core.v | 23 --- vlib/x/encoding/asn1/element.v | 24 --- vlib/x/encoding/asn1/element_decode.v | 21 +-- vlib/x/encoding/asn1/element_encode.v | 3 +- vlib/x/encoding/asn1/errors.v | 50 ------ vlib/x/encoding/asn1/examples/examples0.v | 41 ++--- vlib/x/encoding/asn1/examples/examples2.v | 31 +--- vlib/x/encoding/asn1/examples/examples3.v | 2 +- vlib/x/encoding/asn1/extra0_test.v | 115 ------------ vlib/x/encoding/asn1/extra1_test.v | 207 ---------------------- vlib/x/encoding/asn1/integer.v | 14 ++ vlib/x/encoding/asn1/null.v | 13 +- vlib/x/encoding/asn1/oid.v | 7 +- vlib/x/encoding/asn1/oid_test.v | 2 +- vlib/x/encoding/asn1/other_element.v | 6 +- vlib/x/encoding/asn1/sequence_test.v | 12 +- vlib/x/encoding/asn1/set_test.v | 4 +- vlib/x/encoding/asn1/tagged_test.v | 4 +- 21 files changed, 62 insertions(+), 539 deletions(-) delete mode 100644 vlib/x/encoding/asn1/errors.v delete mode 100644 vlib/x/encoding/asn1/extra0_test.v delete mode 100644 vlib/x/encoding/asn1/extra1_test.v diff --git a/vlib/x/encoding/asn1/bitstring.v b/vlib/x/encoding/asn1/bitstring.v index 6c371b95d..0cf318b6c 100644 --- a/vlib/x/encoding/asn1/bitstring.v +++ b/vlib/x/encoding/asn1/bitstring.v @@ -25,6 +25,16 @@ mut: pad u8 // numbers of unused bits } +// data returns underlying BitString data. +pub fn (bs BitString) data() []u8 { + return bs.data +} + +// pad returns underlying BitString pad byte. +pub fn (bs BitString) pad() u8 { + return bs.pad +} + // check performs check internal validity of the BitString data. fn (bs BitString) check() ! { // to align with octet size, ie, 8 in length, pad bits only need maximum 7 bits @@ -147,7 +157,7 @@ fn (bs BitString) bytes_len() int { // Utility function // maximum allowed binary bits string length -const max_bitstring_len = 8192 +const max_bitstring_len = 65536 // valid_bitstring checks whether this s string is a valid of arrays of binary string `0` and `1`. fn valid_bitstring(s string) bool { diff --git a/vlib/x/encoding/asn1/boolean.v b/vlib/x/encoding/asn1/boolean.v index 3852908eb..f90d6049c 100644 --- a/vlib/x/encoding/asn1/boolean.v +++ b/vlib/x/encoding/asn1/boolean.v @@ -62,12 +62,8 @@ fn (b Boolean) payload_with_rule(rule EncodingRule) ![]u8 { return [b.value] } -fn parse_boolean(mut p Parser) !Boolean { - return Boolean.parse(mut p)! -} - // parse tries to read a Boolean type from parser or return error on fails -fn Boolean.parse(mut p Parser) !Boolean { +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') diff --git a/vlib/x/encoding/asn1/boolean_test.v b/vlib/x/encoding/asn1/boolean_test.v index 3aa3bd4bf..a26056741 100644 --- a/vlib/x/encoding/asn1/boolean_test.v +++ b/vlib/x/encoding/asn1/boolean_test.v @@ -36,10 +36,6 @@ fn test_parse_boolean_with_parser() ! { // out := p.read_element[Boolean]()! // assert out.str() == 'Boolean (TRUE)' - // this is OK - out_2nd := parse[Boolean](data, parse_boolean)! - assert out_2nd.str() == 'Boolean (TRUE)' - // THis is ok mut p2 := Parser.new(data) out_3th := Boolean.parse(mut p2)! diff --git a/vlib/x/encoding/asn1/core.v b/vlib/x/encoding/asn1/core.v index 312e5baa0..c88d39373 100644 --- a/vlib/x/encoding/asn1/core.v +++ b/vlib/x/encoding/asn1/core.v @@ -210,11 +210,6 @@ fn (t Tag) str() string { return '${cls}-${form}-${number}' } -// uniqid_with_id the id of this tag for special purposes identifying in decode -fn (t Tag) uniqid_with_id(id string) string { - return '${t.str()}-${id}' -} - // bytes_len tells amount of bytes needed to store tag in base 128 fn (t Tag) bytes_len() int { if t.number == 0 { @@ -525,24 +520,6 @@ fn universal_tag_from_int(v int) !Tag { } } -// Params is optional params passed to encode or decodeing -// of tag, length or ASN.1 element to drive how encoding works. -@[params] -struct Params { -mut: - rule EncodingRule = .der -} - -fn default_params() &Params { - return &Params{} -} - -fn params_with_rule(rule EncodingRule) &Params { - return &Params{ - rule: .der - } -} - // EncodingRule is standard of rule thats drives how some ASN.1 // element was encoded or deserialized. pub enum EncodingRule { diff --git a/vlib/x/encoding/asn1/element.v b/vlib/x/encoding/asn1/element.v index e5f4aeb75..4a39ec174 100644 --- a/vlib/x/encoding/asn1/element.v +++ b/vlib/x/encoding/asn1/element.v @@ -224,11 +224,6 @@ fn (el Element) equal_payload(other Element) bool { return constant_time_compare(x, y) == 1 } -fn Element.parse(mut p Parser) !Element { - el := p.read_tlv()! - return el -} - fn Element.decode(src []u8) !(Element, int) { el, pos := Element.decode_with_rule(src, 0, .der)! return el, pos @@ -305,22 +300,3 @@ pub fn ElementList.from_bytes(src []u8) ![]Element { } return els } - -// Utility function -// -// is_element check whethers T is fullfills Element -fn is_element[T]() bool { - s := $if T is Element { true } $else { false } - return s -} - -fn has_tag_method[T]() bool { - $for method in T.methods { - $if method.name == 'tag' { - $if method.return_type is Tag { - return true - } - } - } - return false -} diff --git a/vlib/x/encoding/asn1/element_decode.v b/vlib/x/encoding/asn1/element_decode.v index e901ac095..82afa218d 100644 --- a/vlib/x/encoding/asn1/element_decode.v +++ b/vlib/x/encoding/asn1/element_decode.v @@ -151,7 +151,7 @@ pub fn (el Element) unwrap_with_field_options(fo FieldOptions) !Element { // checks inner tag from payload tag, _ := Tag.decode_with_rule(el.payload()!, 0, .der)! if !tag.equal(inner_tag) { - asn1_error(.unexpected_tag_value, 'Get unexpected inner tag from payload')! + return error('Get unexpected inner tag from payload') } } inner_form := inner_tag.constructed @@ -177,25 +177,6 @@ pub fn (el Element) unwrap_with_field_options(fo FieldOptions) !Element { // unwrap the provided element, turn into inner element. fn unwrap(el Element, mode TaggedMode, inner_tag Tag) !Element { - if el.tag().class == .universal { - return error('you cant unwrap universal element') - } - if mode == .explicit { - if !el.tag().constructed { - return error('explicit mode should have constructed tag') - } - // checks inner tag within payload - tag, _ := Tag.decode_with_rule(el.payload()!, 0, .der)! - if !tag.equal(inner_tag) { - asn1_error(.unexpected_tag_value, 'Get unexpected inner tag from payload')! - } - } - if mode == .implicit { - // the form should derived from inner element - if el.tag().constructed != inner_tag.constructed { - return error('Different form between element and provided inner_tag') - } - } match mode { .explicit { // el.payload is serialized of inner element diff --git a/vlib/x/encoding/asn1/element_encode.v b/vlib/x/encoding/asn1/element_encode.v index d25ede7a5..fcfa2a016 100644 --- a/vlib/x/encoding/asn1/element_encode.v +++ b/vlib/x/encoding/asn1/element_encode.v @@ -19,7 +19,8 @@ module asn1 // assert out == [u8(0x0C), 0x02, 0x68, 0x69] // ``` pub fn encode(el Element) ![]u8 { - return encode_with_options(el, '')! + // without options, we call `.encode_with_rule` directly on element. + return encode_with_rule(el, .der)! } // `encode_with_options` serializes element into bytes array with options string passed to drive the result. diff --git a/vlib/x/encoding/asn1/errors.v b/vlib/x/encoding/asn1/errors.v deleted file mode 100644 index cf872dd57..000000000 --- a/vlib/x/encoding/asn1/errors.v +++ /dev/null @@ -1,50 +0,0 @@ -module asn1 - -// Unified error handling -// -enum ErrorKind { - // vfmt off - unexpected_tag_value = 0 - unexpected_length_value = 1 - unexpected_limit_exceed = 2 - unexpected_bytes_data = 3 - unexpected_bytes_offset = 4 - unsupported_rule = 5 - unsupported_format = 6 - unexpected_value = 7 - unmeet_requirement = 8 - unallowed_operation = 9 - // vfmt on -} - -fn (ek ErrorKind) str() string { - match ek { - .unexpected_tag_value { return 'unexpected_tag_value' } - .unexpected_length_value { return 'unexpected_length_value' } - .unexpected_limit_exceed { return 'unexpected_limit_exceed' } - .unexpected_bytes_data { return 'unexpected_bytes_data' } - .unexpected_bytes_offset { return 'unexpected_bytes_offset' } - .unsupported_rule { return 'unsupported_rule' } - .unsupported_format { return 'unsupported_format' } - .unexpected_value { return 'unexpected_value' } - .unmeet_requirement { return 'unmeet_requirement' } - .unallowed_operation { return 'unallowed_operation' } - } -} - -struct Asn1Error { - Error - kind ErrorKind - msg string -} - -fn (er Asn1Error) msg() string { - return 'Error: ${er.kind.str()} with error ${er.msg}' -} - -fn asn1_error(kind ErrorKind, msg string) !Asn1Error { - return Asn1Error{ - kind: kind - msg: msg - } -} diff --git a/vlib/x/encoding/asn1/examples/examples0.v b/vlib/x/encoding/asn1/examples/examples0.v index 52a58d654..67592d996 100644 --- a/vlib/x/encoding/asn1/examples/examples0.v +++ b/vlib/x/encoding/asn1/examples/examples0.v @@ -2,35 +2,16 @@ module main import x.encoding.asn1 -// defined type KerberosString = asn1.GeneralString directly -// produces x00000000: at ???: RUNTIME ERROR: invalid memory access -// /tmp/v_0/examples_0.01JBJNNT0EJVN2FRKJ3ZM83EC9.tmp.c:22858: by asn1__Element_encode_with_options -// /tmp/v_0/examples_0.01JBJNNT0EJVN2FRKJ3ZM83EC9.tmp.c:22838: by asn1__encode_with_options -// /tmp/v_0/examples_0.01JBJNNT0EJVN2FRKJ3ZM83EC9.tmp.c:22825: by asn1__encode -// /tmp/v_0/examples_0.01JBJNNT0EJVN2FRKJ3ZM83EC9.tmp.c:28683: by main__KerberosStringList_payload -// /tmp/v_0/examples_0.01JBJNNT0EJVN2FRKJ3ZM83EC9.tmp.c:4319: by main__KerberosStringList_payload_Interface_asn1__Element_method_wrapper -struct KerberosString { - val asn1.GeneralString -} - -fn (k KerberosString) tag() asn1.Tag { - return asn1.default_generalstring_tag -} +// Previously, defined type KerberosString = asn1.GeneralString directly +// without reduplicating required Element methods, would produces +// RUNTIME ERROR: invalid memory access. +// **Updates** +// Its has been resolved in [22901](https://github.com/vlang/v/issues/22901) +// Thanks to @felipensp +type KerberosString = asn1.GeneralString fn KerberosString.new(s string) !KerberosString { - return KerberosString{ - val: asn1.GeneralString.new(s)! - } -} - -fn KerberosString.from_bytes(b []u8) !KerberosString { - return KerberosString{ - val: asn1.GeneralString.new(b.bytestr())! - } -} - -fn (k KerberosString) payload() ![]u8 { - return k.val.payload()! + return KerberosString(asn1.GeneralString.new(s)!) } type KerberosStringList = []KerberosString @@ -70,9 +51,7 @@ fn (pn PrincipalName) tag() asn1.Tag { } fn (pn PrincipalName) payload() ![]u8 { - kd := asn1.KeyDefault(map[string]asn1.Element{}) - // there are some issues with make_payload when your structure contains generic. - // see https://github.com/vlang/v/issues/22721 + kd := asn1.new_key_default() payload := asn1.make_payload[PrincipalName](pn, kd)! return payload } @@ -100,7 +79,7 @@ fn PrincipalName.decode(bytes []u8) !PrincipalName { mut a := []KerberosString{} for item in el_seq.fields() { gst := item.into_object[asn1.GeneralString]()! - obj := KerberosString{gst} + obj := KerberosString(gst) a << obj } diff --git a/vlib/x/encoding/asn1/examples/examples2.v b/vlib/x/encoding/asn1/examples/examples2.v index e52f068c8..4fe6f05a8 100644 --- a/vlib/x/encoding/asn1/examples/examples2.v +++ b/vlib/x/encoding/asn1/examples/examples2.v @@ -166,33 +166,13 @@ fn EmployeeNumber.new(val asn1.Integer) !asn1.ApplicationElement { return asn1.ApplicationElement.from_element(val, 2, .implicit)! } -// Issues: without defines this required tag and payload, this leads into panic RUNTIME ERROR -// 0x00000000: at ???: RUNTIME ERROR: invalid memory access -fn (e EmployeeNumber) tag() asn1.Tag { - return e.RawElement.tag() -} - -fn (e EmployeeNumber) payload() ![]u8 { - return e.RawElement.payload()! -} - -// // Date ::= [APPLICATION 3] IMPLICIT VisibleString -- YYYYMMDD +// Date ::= [APPLICATION 3] IMPLICIT VisibleString -- YYYYMMDD type Date = asn1.ApplicationElement fn Date.new(val asn1.VisibleString) !asn1.ApplicationElement { return asn1.ApplicationElement.from_element(val, 3, .implicit)! } -// Issues: without defines this required tag and payload, this leads into panic RUNTIME ERROR -// 0x00000000: at ???: RUNTIME ERROR: invalid memory access -fn (d Date) tag() asn1.Tag { - return d.RawElement.tag() -} - -fn (d Date) payload() ![]u8 { - return d.RawElement.payload()! -} - // Name ::= [APPLICATION 1] IMPLICIT SEQUENCE { // givenName VisibleString, // initial VisibleString, @@ -204,15 +184,6 @@ fn Name.new(el NameEntry) !asn1.ApplicationElement { return asn1.ApplicationElement.from_element(el, 1, .implicit)! } -// Issues: without defines this required tag and payload, this leads into panic RUNTIME ERROR -fn (n Name) tag() asn1.Tag { - return n.RawElement.tag() -} - -fn (n Name) payload() ![]u8 { - return n.RawElement.payload()! -} - struct NameEntry { given_name asn1.VisibleString initial asn1.VisibleString diff --git a/vlib/x/encoding/asn1/examples/examples3.v b/vlib/x/encoding/asn1/examples/examples3.v index 139feac64..b356b1aed 100644 --- a/vlib/x/encoding/asn1/examples/examples3.v +++ b/vlib/x/encoding/asn1/examples/examples3.v @@ -58,7 +58,7 @@ fn Example.decode(bytes []u8) !Example { oid_tipe := fields[2].unwrap_with_options('context_specific:1;explicit; inner:6')! tipe := oid_tipe.into_object[asn1.ObjectIdentifier]()! - // then build your Example struc + // then build your Example structure ex := Example{ greeting: greeting answer: answer diff --git a/vlib/x/encoding/asn1/extra0_test.v b/vlib/x/encoding/asn1/extra0_test.v deleted file mode 100644 index 35138ce27..000000000 --- a/vlib/x/encoding/asn1/extra0_test.v +++ /dev/null @@ -1,115 +0,0 @@ -module asn1 - -import math.big - -fn test_parse_sequence_match_length() ! { - // from https://en.wikipedia.org/wiki/ASN.1#Example_encoded_in_DER - data := [u8(0x30), 0x13, 0x02, 0x01, 0x05, 0x16, 0x0e, 0x41, 0x6e, 0x79, 0x62, 0x6f, 0x64, - 0x79, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x3f] - - seq, n := Sequence.decode(data)! - assert n == data.len - assert seq.payload()!.len == 19 // 0x13 - assert encoded_len(seq) == 21 - assert seq.tag().tag_class() == .universal - assert seq.tag().is_constructed() == true - assert seq.tag().tag_number() == 16 - - els := seq.fields() - assert els.len == 2 - assert els[0] is Integer - assert els[1] is IA5String - - assert els[0].tag().tag_number() == int(TagType.integer) - assert els[1].tag().tag_number() == int(TagType.ia5string) - assert els[1].payload()! == 'Anybody there?'.bytes() - - /* - 30 — type tag indicating SEQUENCE - 13 — length in octets of value that follows - 02 — type tag indicating INTEGER - 01 — length in octets of value that follows - 05 — value (5) - 16 — type tag indicating IA5String - (IA5 means the full 7-bit ISO 646 set, including variants, - but is generally US-ASCII) - 0e — length in octets of value that follows - 41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f — value ("Anybody there?") - */ -} - -/* -Certificate ::= SEQUENCE { - tbsCertificate TBSCertificate, - signatureAlgorithm AlgorithmIdentifier, - signatureValue BIT STRING } - -TBSCertificate ::= SEQUENCE { - version [0] EXPLICIT Version DEFAULT v1, - serialNumber CertificateSerialNumber, - signature AlgorithmIdentifier, - issuer Name,SubjectPublicKeyInfo - validity Validity, - subject Name, - subjectPublicKeyInfo SubjectPublicKeyInfo, - issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL, - -- If present, version MUST be v2 or v3 - subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL, - -- If present, version MUST be v2 or v3 - extensions [3] EXPLICIT Extensions OPTIONAL - -- If present, version MUST be v3 } - -Validity ::= SEQUENCE { - notBefore Time, - notAfter Time } - -AlgorithmIdentifier ::= SEQUENCE { - algorithm OBJECT IDENTIFIER, - parameters ANY DEFINED BY algorithm OPTIONAL - } -*/ - -// FIXED: NOTE: Need to be fixed -fn test_x509_certificate_version() ! { - // version [0] EXPLICIT Version DEFAULT v1, - // Version ::= INTEGER { v1(0), v2(1), v3(2) } - val := Integer.from_int(2) - version := ContextElement.explicit_context(val, 0)! - - out := encode(version)! - exp := [u8(0xA0), 0x03, 0x02, 0x01, 0x02] - - assert out == exp -} - -fn test_x509_certificate_signature() ! { - // signature AlgorithmIdentifier, - // AlgorithmIdentifier ::= SEQUENCE { - // algorithm OBJECT IDENTIFIER, - // parameters ANY DEFINED BY algorithm OPTIONAL - // } - oid := ObjectIdentifier.new('1.3.101.112')! - - mut seq := Sequence{} - seq.add_element(oid)! - - out := encode(seq)! - exp := [u8(0x30), 0x05, 0x06, 0x03, 0x2B, 0x65, 0x70] - - assert out == exp - seqback := decode(exp)! - - assert seqback.equal(seq) -} - -fn test_x509_certificate_serialnumber() ! { - // serialNumber CertificateSerialNumber, - // CertificateSerialNumber ::= INTEGER - sn := Integer.from_bigint(big.integer_from_string('711090297755414526861352146244170174161660335942')!) - - mut out := encode(sn)! - exp := [u8(0x02), 0x14, 0x7C, 0x8E, 0x64, 0x49, 0xD7, 0x0E, 0xD9, 0x2D, 0x3E, 0x2E, 0x4A, 0x5D, - 0x2F, 0x76, 0xF6, 0x55, 0x42, 0x46, 0xD7, 0x46] - - assert out == exp -} diff --git a/vlib/x/encoding/asn1/extra1_test.v b/vlib/x/encoding/asn1/extra1_test.v deleted file mode 100644 index dc4206796..000000000 --- a/vlib/x/encoding/asn1/extra1_test.v +++ /dev/null @@ -1,207 +0,0 @@ -module asn1 - -import encoding.hex -import crypto.pem - -fn test_rsa_public_key() ! { - // from https://asecuritysite.com/digitalcert/sigs4cd - /* - // from https://asecuritysite.com/ecc/sigs4?a0=30819f300d06092a864886f70d010101050003818d0030818902818100a399caf6d93b62a6b6a5311efe93c4d647397ca05a98fa5cddb72d6816ab16fc85f940efe9cf2233975c8925c60f4cd356767cc8445686313a0caeae32930070ca90591a1b249c2fcef9280f5a11d8f1990579d86a05b2523f52c4a876da2d635ca27fbff195e6f7015f834928f033a20b2cd0216a852958b3e58d0f9bd542330203010001 - DER: 30819f300d06092a864886f70d010101050003818d0030818902818100a399caf6d93b62a6b6a5311efe93c4d647397ca05a98fa5cddb72d6816ab16fc85f940efe9cf2233975c8925c60f4cd356767cc8445686313a0caeae32930070ca90591a1b249c2fcef9280f5a11d8f1990579d86a05b2523f52c4a876da2d635ca27fbff195e6f7015f834928f033a20b2cd0216a852958b3e58d0f9bd542330203010001 - -[U] SEQUENCE (30) - [U] SEQUENCE (30) - [U] OBJECT (06): 1.2.840.113549.1.1.1 - RSA Encryption - [U] NULL: None - [U] BIT STRING (03): 0xb'0030818902818100A399CAF6D93B62A6B6A5311EFE93C4D647397CA05A98FA5CDDB72D6816AB16FC85F940EFE9CF2233975C8925C60F4CD356767CC8445686313A0CAEAE32930070CA90591A1B249C2FCEF9280F5A11D8F1990579D86A05B2523F52C4A876DA2D635CA27FBFF195E6F7015F834928F033A20B2CD0216A852958B3E58D0F9BD542330203010001' -81 - RSA Modulus (1024) bits: a399caf6d93b62a6b6a5311efe93c4d647397ca05a98fa5cddb72d6816ab16fc85f940efe9cf2233975c8925c60f4cd356767cc8445686313a0caeae32930070ca90591a1b249c2fcef9280f5a11d8f1990579d86a05b2523f52c4a876da2d635ca27fbff195e6f7015f834928f033a20b2cd0216a852958b3e58d0f9bd54233 -RSA e: 10001 - ------BEGIN PUBLIC KEY----- -MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjmcr22TtipralMR7+k8TWRzl8oFqY+lzdty1oFqsW/IX5QO/pzyIzl1yJJcYPTNNWdnzIRFaGMToMrq4ykwBwypBZGhsknC/O+SgPWhHY8ZkFedhqBbJSP1LEqHbaLWNcon+/8ZXm9wFfg0ko8DOiCyzQIWqFKViz5Y0Pm9VCMwIDAQAB ------END PUBLIC KEY----- - */ - data := '30819f300d06092a864886f70d010101050003818d0030818902818100a399caf6d93b62a6b6a5311efe93c4d647397ca05a98fa5cddb72d6816ab16fc85f940efe9cf2233975c8925c60f4cd356767cc8445686313a0caeae32930070ca90591a1b249c2fcef9280f5a11d8f1990579d86a05b2523f52c4a876da2d635ca27fbff195e6f7015f834928f033a20b2cd0216a852958b3e58d0f9bd542330203010001' - - bytes := hex.decode(data)! - seq, n := Sequence.decode(bytes)! - - els := seq.fields() - assert els.len == 2 - assert els[0] is Sequence - assert els[1] is BitString - - els0 := els[0] as Sequence - assert els0.fields.len == 2 - assert els0.fields[0] is ObjectIdentifier - oid := els0.fields[0] as ObjectIdentifier - assert oid.str() == 'OID (1.2.840.113549.1.1.1)' - assert els0.fields[1] is Null -} - -// NOTE: Need to be fixed -fn test_x25519_private_key() ! { - // taken from https://www.rfc-editor.org/rfc/rfc8410#section-10 - // 10.3 Examples of Ed25519 Private Key - - data := '-----BEGIN PRIVATE KEY----- -MC4CAQAwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC ------END PRIVATE KEY-----' - - // The same item dumped as asn1 yields: - /* - 0 30 46: SEQUENCE { - 2 02 1: INTEGER 0 - 5 30 5: SEQUENCE { - 7 06 3: OBJECT IDENTIFIER - : Ed 25519 signature algorithm { 1 3 101 112 } - : } - 12 04 34: OCTET STRING - : 04 20 D4 EE 72 DB F9 13 58 4A D5 B6 D8 F1 F7 69 - : F8 AD 3A FE 7C 28 CB F1 D4 FB E0 97 A8 8F 44 75 - : 58 42 - : } - */ - block, _ := pem.decode(data)? - - seq, n := Sequence.decode(block.data)! - - assert seq.payload()!.len == 46 - - els := seq.fields() - assert els[0] is Integer - assert els[1] is Sequence - b := els[1] as Sequence - - assert b.fields()[0] is ObjectIdentifier - assert b.fields()[0].length()! == 3 - - oid := b.fields()[0] as ObjectIdentifier - assert oid.str() == 'OID (1.3.101.112)' - - assert els[2] is OctetString - assert els[2].payload()!.len == 34 -} - -/* -// NEED TO BE FIXED -// TODO: This test still failed on `Sequence.parse_contents` with error `next: truncated bytes` -// FIXME: need to be investigated, bad data, or sequence handling or others source of fail -// so just disable this test, would be moved into related module when ready -fn test_example_x25519_certificate() { - // taken from https://www.rfc-editor.org/rfc/rfc8410.html#section-10 - // 10.2. Example X25519 Certificate - data := '-----BEGIN CERTIFICATE----- -MIIBLDCB36ADAgECAghWAUdKKo3DMDAFBgMrZXAwGTEXMBUGA1UEAwwOSUVURiBUZX -N0IERlbW8wHhcNMTYwODAxMTIxOTI0WhcNNDAxMjMxMjM1OTU5WjAZMRcwFQYDVQQD -DA5JRVRGIFRlc3QgRGVtbzAqMAUGAytlbgMhAIUg8AmJMKdUdIt93LQ+91oNvzoNJj -ga9OukqY6qm05qo0UwQzAPBgNVHRMBAf8EBTADAQEAMA4GA1UdDwEBAAQEAwIDCDAg -BgNVHQ4BAQAEFgQUmx9e7e0EM4Xk97xiPFl1uQvIuzswBQYDK2VwA0EAryMB/t3J5v -/BzKc9dNZIpDmAgs3babFOTQbs+BolzlDUwsPrdGxO3YNGhW7Ibz3OGhhlxXrCe1Cg -w1AH9efZBw== ------END CERTIFICATE-----' - - // The same item dumped as asn1 yields: - /* - 0 300: SEQUENCE { - 4 223: SEQUENCE { - 7 3: [0] { - 9 1: INTEGER 2 - : } - 12 8: INTEGER 56 01 47 4A 2A 8D C3 30 - 22 5: SEQUENCE { - 24 3: OBJECT IDENTIFIER - : Ed 25519 signature algorithm { 1 3 101 112 } - : } - 29 25: SEQUENCE { - 31 23: SET { - 33 21: SEQUENCE { - 35 3: OBJECT IDENTIFIER commonName (2 5 4 3) - 40 14: UTF8String 'IETF Test Demo' - : } - : } - : } - 56 30: SEQUENCE { - 58 13: UTCTime 01/08/2016 12:19:24 GMT - 73 13: UTCTime 31/12/2040 23:59:59 GMT - : } - 88 25: SEQUENCE { - 90 23: SET { - 92 21: SEQUENCE { - 94 3: OBJECT IDENTIFIER commonName (2 5 4 3) - 99 14: UTF8String 'IETF Test Demo' - : } - : } - : } - 115 42: SEQUENCE { - 117 5: SEQUENCE { - 119 3: OBJECT IDENTIFIER - : ECDH 25519 key agreement { 1 3 101 110 } - : } - 124 33: BIT STRING - : 85 20 F0 09 89 30 A7 54 74 8B 7D DC B4 3E F7 5A - : 0D BF 3A 0D 26 38 1A F4 EB A4 A9 8E AA 9B 4E 6A - : } - 159 69: [3] { - 161 67: SEQUENCE { - 163 15: SEQUENCE { - 165 3: OBJECT IDENTIFIER basicConstraints (2 5 29 19) - 170 1: BOOLEAN TRUE - 173 5: OCTET STRING, encapsulates { - 175 3: SEQUENCE { - 177 1: BOOLEAN FALSE - : } - : } - : } - 180 14: SEQUENCE { - 182 3: OBJECT IDENTIFIER keyUsage (2 5 29 15) - 187 1: BOOLEAN FALSE - 190 4: OCTET STRING, encapsulates { - 192 2: BIT STRING 3 unused bits - : '10000'B (bit 4) - : } - : } - 196 32: SEQUENCE { - 198 3: OBJECT IDENTIFIER subjectKeyIdentifier (2 5 29 14) - 203 1: BOOLEAN FALSE - 206 22: OCTET STRING, encapsulates { - 208 20: OCTET STRING - : 9B 1F 5E ED ED 04 33 85 E4 F7 BC 62 3C 59 75 - : B9 0B C8 BB 3B - : } - : } - : } - : } - : } - 230 5: SEQUENCE { - 232 3: OBJECT IDENTIFIER - : Ed 25519 signature algorithm { 1 3 101 112 } - : } - 237 65: BIT STRING - : AF 23 01 FE DD C9 E6 FF C1 CC A7 3D 74 D6 48 A4 - : 39 80 82 CD DB 69 B1 4E 4D 06 EC F8 1A 25 CE 50 - : D4 C2 C3 EB 74 6C 4E DD 83 46 85 6E C8 6F 3D CE - : 1A 18 65 C5 7A C2 7B 50 A0 C3 50 07 F5 E7 D9 07 - : } - */ - block, _ := pem.decode(data)? - seq, n := Sequence.decode(block.data)! - - assert seq.payload()!.len == 302 - - // certificate is arrays of 3 element - assert seq.fields().len == 3 - - els := seq.fields() - // last element - assert els[2] is BitString - bts := BitString.from_bytes(seq.fields[2].payload()!)! - exp := [u8(0xAF), 0x23, 0x01, 0xFE, 0xDD, 0xC9, 0xE6, 0xFF, 0xC1, 0xCC, 0xA7, 0x3D, 0x74, 0xD6, - 0x48, 0xA4, 0x39, 0x80, 0x82, 0xCD, 0xDB, 0x69, 0xB1, 0x4E, 0x4D, 0x06, 0xEC, 0xF8, 0x1A, - 0x25, 0xCE, 0x50, 0xD4, 0xC2, 0xC3, 0xEB, 0x74, 0x6C, 0x4E, 0xDD, 0x83, 0x46, 0x85, 0x6E, - 0xC8, 0x6F, 0x3D, 0xCE, 0x1A, 0x18, 0x65, 0xC5, 0x7A, 0xC2, 0x7B, 0x50, 0xA0, 0xC3, 0x50, - 0x07, 0xF5, 0xE7, 0xD9, 0x07] - assert bts.data == exp -} -*/ diff --git a/vlib/x/encoding/asn1/integer.v b/vlib/x/encoding/asn1/integer.v index 6f89e2b09..7ba78cd1c 100644 --- a/vlib/x/encoding/asn1/integer.v +++ b/vlib/x/encoding/asn1/integer.v @@ -36,6 +36,20 @@ pub: value IntValue } +// hex returns Integer value as a hex string. +pub fn (v Integer) hex() string { + match v.value { + i64 { + val := v.value as i64 + return val.hex_full() + } + big.Integer { + val := v.value as big.Integer + return val.hex() + } + } +} + fn (v Integer) str() string { return 'Integer ${v.value.str()}' } diff --git a/vlib/x/encoding/asn1/null.v b/vlib/x/encoding/asn1/null.v index a923a1efa..cac3c3feb 100644 --- a/vlib/x/encoding/asn1/null.v +++ b/vlib/x/encoding/asn1/null.v @@ -13,11 +13,6 @@ pub const default_null_tag = Tag{.universal, false, int(TagType.null)} // The NULL type can be used in situations where the presence of a type is important, but no concrete value is needed. pub struct Null {} -// new creates a Null element. -pub fn Null.new() Null { - return Null{} -} - // tag returns the tag of Null element. pub fn (n Null) tag() Tag { return default_null_tag @@ -42,9 +37,7 @@ fn Null.parse(mut p Parser) !Null { if length != 0 { return error('Get unexpected non-null length for Null type') } - null := Null.new() - - return null + return Null{} } // Null.decode read Null from bytes. @@ -62,10 +55,6 @@ fn Null.decode(bytes []u8) !(Null, int) { } fn Null.from_bytes(b []u8) !Null { - return Null.from_bytes_with_rule(b, .der)! -} - -fn Null.from_bytes_with_rule(b []u8, rule EncodingRule) !Null { if b.len != 0 { return error('Null: bad non-null bytes') } diff --git a/vlib/x/encoding/asn1/oid.v b/vlib/x/encoding/asn1/oid.v index bd53f7198..c8c41b196 100644 --- a/vlib/x/encoding/asn1/oid.v +++ b/vlib/x/encoding/asn1/oid.v @@ -17,6 +17,11 @@ mut: value []int } +// value returns underlying ObjectIdentifier values as arrays of int. +pub fn (o ObjectIdentifier) value() []int { + return o.value +} + // tag returns the tag of ObjectIdentifier type. pub fn (oid ObjectIdentifier) tag() Tag { return default_oid_tag @@ -179,7 +184,7 @@ fn (oid ObjectIdentifier) str() string { } res := s.join('.') - return 'OID (${res})' + return '${res}' } fn (oid ObjectIdentifier) validate() bool { diff --git a/vlib/x/encoding/asn1/oid_test.v b/vlib/x/encoding/asn1/oid_test.v index 2b21c534d..035d264e9 100644 --- a/vlib/x/encoding/asn1/oid_test.v +++ b/vlib/x/encoding/asn1/oid_test.v @@ -210,7 +210,7 @@ fn test_oid_encode_decode() ! { oidback, _ := ObjectIdentifier.decode(out)! - assert oidback.str() == 'OID ' + '(${inp})' + assert oidback.str() == '${inp}' assert oidback.tag().tag_number() == 6 } diff --git a/vlib/x/encoding/asn1/other_element.v b/vlib/x/encoding/asn1/other_element.v index 747db01ae..267d213da 100644 --- a/vlib/x/encoding/asn1/other_element.v +++ b/vlib/x/encoding/asn1/other_element.v @@ -190,7 +190,7 @@ fn (mut r RawElement) set_default_value_with_flag(value Element, force bool) ! { // inner_tag returns the inner tag of the RawElement if it exists, or error on fails. pub fn (r RawElement) inner_tag() !Tag { - inner_tag := r.inner_tag or { return asn1_error(.unexpected_value, ' r.inner_tag is not set')! } + inner_tag := r.inner_tag or { return error(' r.inner_tag is not set') } return inner_tag } @@ -198,14 +198,14 @@ pub fn (r RawElement) inner_tag() !Tag { // inner_element returns the inner element of the RawElement if its exists. pub fn (r RawElement) inner_element() !Element { if r.tag.class == .universal { - asn1_error(.unallowed_operation, 'inner element from universal class is not availables')! + return error('inner element from universal class is not availables') } mode := r.mode or { return err } inner_tag := r.inner_tag or { return err } if mode == .explicit { if !r.tag.constructed { - asn1_error(.unmeet_requirement, 'tag should be constructed when in explicit')! + return error('tag should be constructed when in explicit') } } // in implicit, r.content is inner element content with inner tag diff --git a/vlib/x/encoding/asn1/sequence_test.v b/vlib/x/encoding/asn1/sequence_test.v index 8a633cef9..3726c7ffe 100644 --- a/vlib/x/encoding/asn1/sequence_test.v +++ b/vlib/x/encoding/asn1/sequence_test.v @@ -33,7 +33,7 @@ fn test_sequence_contains_other_seq() ! { mut seq1 := Sequence{} // add two primitive elements to the sequence seq1.add_element(Boolean.new(true))! - seq1.add_element(Null.new())! + seq1.add_element(Null{})! seq1.add_element(Boolean.new(false))! // lets create another sequences, where it contains primitive element and first sequence created above. @@ -88,7 +88,7 @@ fn test_sequence_der_decode() ! { fn test_sequence_add_and_encode_boolean() { o1 := Boolean.new(false) o2 := Boolean.new(true) - o3 := Null.new() + o3 := Null{} mut seq := Sequence{} seq.add_element(o1)! seq.add_element(o2)! @@ -204,7 +204,7 @@ fn test_sequence_integer_bigint() ! { o1 := Integer.from_bigint(inp) o2 := Boolean.new(true) - o3 := Null.new() + o3 := Null{} seq.add_element(o1)! seq.add_element(o2)! seq.add_element(o3)! @@ -240,7 +240,7 @@ fn test_sequence_integer_bigint() ! { fn test_sequence_of_string() ! { str := 'iloveyou' // 8 mut seq := Sequence.new()! - o1 := Null.new() + o1 := Null{} o2 := Utf8String.new(str)! o3 := IA5String.new(str)! seq.add_element(o1)! @@ -266,7 +266,7 @@ fn test_sequence_of_string() ! { fn test_sequnce_of_sequence() { mut seq := Sequence.new()! - seq.add_element(Null.new())! + seq.add_element(Null{})! seq.add_element(Boolean.new(false))! mut out := encode(seq)! @@ -338,7 +338,7 @@ fn test_sequence_algorithm_identifier() ! { 0x05, 0x00] algo := AlgorithmIdentifier{ algorithm: ObjectIdentifier.new('1.2.840.113549.1.1.11')! - parameters: AnyDefinedBy.new(Null.new()) + parameters: AnyDefinedBy.new(Null{}) } out := encode(algo)! assert out == expected diff --git a/vlib/x/encoding/asn1/set_test.v b/vlib/x/encoding/asn1/set_test.v index 3bc0bd1f9..f6de8d3a9 100644 --- a/vlib/x/encoding/asn1/set_test.v +++ b/vlib/x/encoding/asn1/set_test.v @@ -9,7 +9,7 @@ fn test_sort_the_set() { val12 := Integer.from_i64(12) val32 := Integer.from_i64(32) valbol := Boolean.new(false) - valnull := Null.new() + valnull := Null{} valapp := RawElement.new(Tag{.application, false, 34}, [u8(44), 45])! valctx := RawElement.new(Tag{.context_specific, false, 35}, [u8(50), 55])! @@ -74,7 +74,7 @@ fn test_set_encode() ! { mut set1 := Set.new()! set1.add_element(Boolean.new(false))! - set1.add_element(Null.new())! + set1.add_element(Null{})! set1.add_element(Integer.from_int(4))! // boolean tag:1 length: 3, integer tag:2 length: 3, null tag: 5 length: 2, total length: 8 // so, it should sort to diff --git a/vlib/x/encoding/asn1/tagged_test.v b/vlib/x/encoding/asn1/tagged_test.v index 244a5acb3..12dfa442f 100644 --- a/vlib/x/encoding/asn1/tagged_test.v +++ b/vlib/x/encoding/asn1/tagged_test.v @@ -4,7 +4,7 @@ module asn1 fn test_explicit_context_null_pack_unpack() ! { - el := Null.new() + el := Null{} ex1 := ContextElement.from_element(el, 0, .explicit)! out := encode(ex1)! @@ -21,7 +21,7 @@ fn test_explicit_context_null_pack_unpack() ! { } fn test_explicit_context_nested_pack_unpack() ! { - el := Null.new() + el := Null{} ex1 := ContextElement.from_element(el, 1, .explicit)! -- 2.39.5