| // Copyright 2017 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 cryptobyte_test | |
| import ( | |
| "errors" | |
| "fmt" | |
| "internal/x/crypto/cryptobyte" | |
| "internal/x/crypto/cryptobyte/asn1" | |
| ) | |
| func ExampleString_lengthPrefixed() { | |
| // This is an example of parsing length-prefixed data (as found in, for | |
| // example, TLS). Imagine a 16-bit prefixed series of 8-bit prefixed | |
| // strings. | |
| input := cryptobyte.String([]byte{0, 12, 5, 'h', 'e', 'l', 'l', 'o', 5, 'w', 'o', 'r', 'l', 'd'}) | |
| var result []string | |
| var values cryptobyte.String | |
| if !input.ReadUint16LengthPrefixed(&values) || | |
| !input.Empty() { | |
| panic("bad format") | |
| } | |
| for !values.Empty() { | |
| var value cryptobyte.String | |
| if !values.ReadUint8LengthPrefixed(&value) { | |
| panic("bad format") | |
| } | |
| result = append(result, string(value)) | |
| } | |
| // Output: []string{"hello", "world"} | |
| fmt.Printf("%#v\n", result) | |
| } | |
| func ExampleString_aSN1() { | |
| // This is an example of parsing ASN.1 data that looks like: | |
| // Foo ::= SEQUENCE { | |
| // version [6] INTEGER DEFAULT 0 | |
| // data OCTET STRING | |
| // } | |
| input := cryptobyte.String([]byte{0x30, 12, 0xa6, 3, 2, 1, 2, 4, 5, 'h', 'e', 'l', 'l', 'o'}) | |
| var ( | |
| version int64 | |
| data, inner, versionBytes cryptobyte.String | |
| haveVersion bool | |
| ) | |
| if !input.ReadASN1(&inner, asn1.SEQUENCE) || | |
| !input.Empty() || | |
| !inner.ReadOptionalASN1(&versionBytes, &haveVersion, asn1.Tag(6).Constructed().ContextSpecific()) || | |
| (haveVersion && !versionBytes.ReadASN1Integer(&version)) || | |
| (haveVersion && !versionBytes.Empty()) || | |
| !inner.ReadASN1(&data, asn1.OCTET_STRING) || | |
| !inner.Empty() { | |
| panic("bad format") | |
| } | |
| // Output: haveVersion: true, version: 2, data: hello | |
| fmt.Printf("haveVersion: %t, version: %d, data: %s\n", haveVersion, version, string(data)) | |
| } | |
| func ExampleBuilder_aSN1() { | |
| // This is an example of building ASN.1 data that looks like: | |
| // Foo ::= SEQUENCE { | |
| // version [6] INTEGER DEFAULT 0 | |
| // data OCTET STRING | |
| // } | |
| version := int64(2) | |
| data := []byte("hello") | |
| const defaultVersion = 0 | |
| var b cryptobyte.Builder | |
| b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) { | |
| if version != defaultVersion { | |
| b.AddASN1(asn1.Tag(6).Constructed().ContextSpecific(), func(b *cryptobyte.Builder) { | |
| b.AddASN1Int64(version) | |
| }) | |
| } | |
| b.AddASN1OctetString(data) | |
| }) | |
| result, err := b.Bytes() | |
| if err != nil { | |
| panic(err) | |
| } | |
| // Output: 300ca603020102040568656c6c6f | |
| fmt.Printf("%x\n", result) | |
| } | |
| func ExampleBuilder_lengthPrefixed() { | |
| // This is an example of building length-prefixed data (as found in, | |
| // for example, TLS). Imagine a 16-bit prefixed series of 8-bit | |
| // prefixed strings. | |
| input := []string{"hello", "world"} | |
| var b cryptobyte.Builder | |
| b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | |
| for _, value := range input { | |
| b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { | |
| b.AddBytes([]byte(value)) | |
| }) | |
| } | |
| }) | |
| result, err := b.Bytes() | |
| if err != nil { | |
| panic(err) | |
| } | |
| // Output: 000c0568656c6c6f05776f726c64 | |
| fmt.Printf("%x\n", result) | |
| } | |
| func ExampleBuilder_lengthPrefixOverflow() { | |
| // Writing more data that can be expressed by the length prefix results | |
| // in an error from Bytes(). | |
| tooLarge := make([]byte, 256) | |
| var b cryptobyte.Builder | |
| b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) { | |
| b.AddBytes(tooLarge) | |
| }) | |
| result, err := b.Bytes() | |
| fmt.Printf("len=%d err=%s\n", len(result), err) | |
| // Output: len=0 err=cryptobyte: pending child length 256 exceeds 1-byte length prefix | |
| } | |
| func ExampleBuilderContinuation_errorHandling() { | |
| var b cryptobyte.Builder | |
| // Continuations that panic with a BuildError will cause Bytes to | |
| // return the inner error. | |
| b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) { | |
| b.AddUint32(0) | |
| panic(cryptobyte.BuildError{Err: errors.New("example error")}) | |
| }) | |
| result, err := b.Bytes() | |
| fmt.Printf("len=%d err=%s\n", len(result), err) | |
| // Output: len=0 err=example error | |
| } |