├── AUTHORS ├── CONTRIBUTORS ├── README.md ├── CONTRIBUTING.md ├── der2ascii ├── main.go ├── decoder.go ├── writer_test.go ├── writer.go └── decoder_test.go ├── ascii2der ├── main.go ├── values.go ├── values_test.go ├── encoder.go ├── encoder_test.go ├── scanner_test.go └── scanner.go ├── lib ├── tag_test.go └── tag.go ├── language.txt └── LICENSE /AUTHORS: -------------------------------------------------------------------------------- 1 | # This is the official list of DER ASCII authors for copyright purposes. 2 | # This file is distinct from the CONTRIBUTORS files. 3 | # See the latter for an explanation. 4 | # Names should be added to this file as: 5 | # Name or Organization 6 | # The email address is not required for organizations. 7 | Google Inc. 8 | -------------------------------------------------------------------------------- /CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | # People who have agreed to one of the CLAs and can contribute patches. 2 | # The AUTHORS file lists the copyright holders; this file 3 | # lists people. For example, Google employees are listed here 4 | # but not in AUTHORS, because Google holds the copyright. 5 | # 6 | # https://developers.google.com/open-source/cla/individual 7 | # https://developers.google.com/open-source/cla/corporate 8 | # 9 | # Names should be added to this file as: 10 | # Name 11 | 12 | David Benjamin 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DER ASCII 2 | 3 | DER ASCII is a small human-editable language to emit DER-like output. Its goal 4 | is to help create test inputs by taking an existing DER or BER structure, 5 | disassembling it into DER ASCII, making adjustments, and assembling back into 6 | DER. This avoids having to manually fix up all the length prefixes. As a bonus, 7 | it acts as a human-readable view for DER structures. 8 | 9 | For the language specification, see [language.txt](/language.txt). 10 | 11 | This project provides two tools, `ascii2der` and `der2ascii`, to convert DER 12 | ASCII to a byte string and vice versa. To install them, run: 13 | 14 | go get github.com/google/der-ascii/... 15 | 16 | This is not an official Google project. 17 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Want to contribute? Great! First, read this page (including the small print at the end). 2 | 3 | ### Before you contribute 4 | Before we can use your code, you must sign the 5 | [Google Individual Contributor License Agreement] 6 | (https://cla.developers.google.com/about/google-individual) 7 | (CLA), which you can do online. The CLA is necessary mainly because you own the 8 | copyright to your changes, even after your contribution becomes part of our 9 | codebase, so we need your permission to use and distribute your code. We also 10 | need to be sure of various other things—for instance that you'll tell us if you 11 | know that your code infringes on other people's patents. You don't have to sign 12 | the CLA until after you've submitted your code for review and a member has 13 | approved it, but you must do it before we can put your code into our codebase. 14 | Before you start working on a larger contribution, you should get in touch with 15 | us first through the issue tracker with your idea so that we can help out and 16 | possibly guide you. Coordinating up front makes it much easier to avoid 17 | frustration later on. 18 | 19 | ### Code reviews 20 | All submissions, including submissions by project members, require review. We 21 | use Github pull requests for this purpose. 22 | 23 | ### The small print 24 | Contributions made by corporations are covered by a different agreement than 25 | the one above, the 26 | [Software Grant and Corporate Contributor License Agreement] 27 | (https://cla.developers.google.com/about/google-corporate). 28 | -------------------------------------------------------------------------------- /der2ascii/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The DER ASCII Authors. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "flag" 19 | "fmt" 20 | "io/ioutil" 21 | "os" 22 | ) 23 | 24 | var inPath = flag.String("i", "", "input file to use (defaults to stdin)") 25 | var outPath = flag.String("o", "", "output file to use (defaults to stdout)") 26 | 27 | func main() { 28 | flag.Parse() 29 | 30 | if flag.NArg() > 0 { 31 | fmt.Fprintf(os.Stderr, "Usage: %s [-i INPUT] [-o OUTPUT]\n", os.Args[0]) 32 | os.Exit(1) 33 | } 34 | 35 | inFile := os.Stdin 36 | if *inPath != "" { 37 | var err error 38 | inFile, err = os.Open(*inPath) 39 | if err != nil { 40 | fmt.Fprintf(os.Stderr, "Error opening %s: %s\n", *inPath, err) 41 | os.Exit(1) 42 | } 43 | defer inFile.Close() 44 | } 45 | 46 | inBytes, err := ioutil.ReadAll(inFile) 47 | if err != nil { 48 | fmt.Fprintf(os.Stderr, "Error reading input: %s\n", err) 49 | os.Exit(1) 50 | } 51 | 52 | outFile := os.Stdout 53 | if *outPath != "" { 54 | outFile, err = os.Create(*outPath) 55 | if err != nil { 56 | fmt.Fprintf(os.Stderr, "Error opening %s: %s\n", *outPath, err) 57 | os.Exit(1) 58 | } 59 | defer outFile.Close() 60 | } 61 | _, err = outFile.Write([]byte(derToASCII(inBytes))) 62 | if err != nil { 63 | fmt.Fprintf(os.Stderr, "Error writing output: %s\n", err) 64 | os.Exit(1) 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /ascii2der/main.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The DER ASCII Authors. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "flag" 19 | "fmt" 20 | "io/ioutil" 21 | "os" 22 | ) 23 | 24 | var inPath = flag.String("i", "", "input file to use (defaults to stdin)") 25 | var outPath = flag.String("o", "", "output file to use (defaults to stdout)") 26 | 27 | func main() { 28 | flag.Parse() 29 | 30 | if flag.NArg() > 0 { 31 | fmt.Fprintf(os.Stderr, "Usage: %s [-i INPUT] [-o OUTPUT]\n", os.Args[0]) 32 | os.Exit(1) 33 | } 34 | 35 | inFile := os.Stdin 36 | if *inPath != "" { 37 | var err error 38 | inFile, err = os.Open(*inPath) 39 | if err != nil { 40 | fmt.Fprintf(os.Stderr, "Error opening %s: %s\n", *inPath, err) 41 | os.Exit(1) 42 | } 43 | defer inFile.Close() 44 | } 45 | 46 | inBytes, err := ioutil.ReadAll(inFile) 47 | if err != nil { 48 | fmt.Fprintf(os.Stderr, "Error reading input: %s\n", err) 49 | os.Exit(1) 50 | } 51 | 52 | outBytes, err := asciiToDER(string(inBytes)) 53 | if err != nil { 54 | fmt.Fprintf(os.Stderr, "Syntax error: %s\n", err) 55 | os.Exit(1) 56 | } 57 | 58 | outFile := os.Stdout 59 | if *outPath != "" { 60 | var err error 61 | outFile, err = os.Create(*outPath) 62 | if err != nil { 63 | fmt.Fprintf(os.Stderr, "Error opening %s: %s\n", *outPath, err) 64 | os.Exit(1) 65 | } 66 | defer outFile.Close() 67 | } 68 | _, err = outFile.Write(outBytes) 69 | if err != nil { 70 | fmt.Fprintf(os.Stderr, "Error writing output: %s\n", err) 71 | os.Exit(1) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /ascii2der/values.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The DER ASCII Authors. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "errors" 19 | "fmt" 20 | "strconv" 21 | "strings" 22 | 23 | "github.com/google/der-ascii/lib" 24 | ) 25 | 26 | // decodeTagString decodes s as a tag descriptor and returns the decoded tag or 27 | // an error. 28 | func decodeTagString(s string) (lib.Tag, error) { 29 | ss := strings.Split(s, " ") 30 | 31 | // Tag aliases may only be in the first component. 32 | tag, ok := lib.TagByName(ss[0]) 33 | if ok { 34 | ss = ss[1:] 35 | goto constructedOrPrimitive 36 | } 37 | 38 | // Tags default to constructed, context-specific. 39 | tag.Class = lib.ClassContextSpecific 40 | tag.Constructed = true 41 | 42 | // Otherwise, the first component is an optional class. 43 | switch ss[0] { 44 | case "APPLICATION": 45 | tag.Class = lib.ClassApplication 46 | ss = ss[1:] 47 | case "PRIVATE": 48 | tag.Class = lib.ClassPrivate 49 | ss = ss[1:] 50 | case "UNIVERSAL": 51 | tag.Class = lib.ClassUniversal 52 | ss = ss[1:] 53 | } 54 | 55 | { 56 | // The next (or first) component must be the tag number. 57 | // Introduce a scope so the goto above is legal. 58 | if len(ss) == 0 { 59 | return lib.Tag{}, errors.New("expected tag number") 60 | } 61 | n, err := strconv.ParseUint(ss[0], 10, 32) 62 | if err != nil { 63 | return lib.Tag{}, err 64 | } 65 | tag.Number = uint32(n) 66 | ss = ss[1:] 67 | } 68 | 69 | constructedOrPrimitive: 70 | // The final token, if any, may be CONSTRUCTED or PRIMITIVE. 71 | if len(ss) > 0 { 72 | switch ss[0] { 73 | case "CONSTRUCTED": 74 | tag.Constructed = true 75 | case "PRIMITIVE": 76 | tag.Constructed = false 77 | default: 78 | return lib.Tag{}, fmt.Errorf("unexpected tag component '%s'", ss[0]) 79 | } 80 | ss = ss[1:] 81 | } 82 | 83 | if len(ss) != 0 { 84 | return lib.Tag{}, fmt.Errorf("excess tag component '%s'", ss[0]) 85 | } 86 | 87 | return tag, nil 88 | } 89 | -------------------------------------------------------------------------------- /ascii2der/values_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The DER ASCII Authors. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "testing" 19 | 20 | "github.com/google/der-ascii/lib" 21 | ) 22 | 23 | var decodeTagStringTests = []struct { 24 | input string 25 | tag lib.Tag 26 | ok bool 27 | }{ 28 | {"SEQUENCE", lib.Tag{lib.ClassUniversal, 16, true}, true}, 29 | {"SEQUENCE CONSTRUCTED", lib.Tag{lib.ClassUniversal, 16, true}, true}, 30 | {"SEQUENCE PRIMITIVE", lib.Tag{lib.ClassUniversal, 16, false}, true}, 31 | {"INTEGER", lib.Tag{lib.ClassUniversal, 2, false}, true}, 32 | {"INTEGER CONSTRUCTED", lib.Tag{lib.ClassUniversal, 2, true}, true}, 33 | {"INTEGER PRIMITIVE", lib.Tag{lib.ClassUniversal, 2, false}, true}, 34 | {"2", lib.Tag{lib.ClassContextSpecific, 2, true}, true}, 35 | {"2 PRIMITIVE", lib.Tag{lib.ClassContextSpecific, 2, false}, true}, 36 | {"APPLICATION 2", lib.Tag{lib.ClassApplication, 2, true}, true}, 37 | {"PRIVATE 2", lib.Tag{lib.ClassPrivate, 2, true}, true}, 38 | {"UNIVERSAL 2", lib.Tag{lib.ClassUniversal, 2, true}, true}, 39 | {"UNIVERSAL 2 CONSTRUCTED", lib.Tag{lib.ClassUniversal, 2, true}, true}, 40 | {"UNIVERSAL 2 PRIMITIVE", lib.Tag{lib.ClassUniversal, 2, false}, true}, 41 | {"UNIVERSAL 2 CONSTRUCTED EXTRA", lib.Tag{}, false}, 42 | {"UNIVERSAL 2 EXTRA", lib.Tag{}, false}, 43 | {"UNIVERSAL NOT_A_NUMBER", lib.Tag{}, false}, 44 | {"UNIVERSAL SEQUENCE", lib.Tag{}, false}, 45 | {"UNIVERSAL", lib.Tag{}, false}, 46 | {"SEQUENCE 2", lib.Tag{}, false}, 47 | {"", lib.Tag{}, false}, 48 | {" SEQUENCE", lib.Tag{}, false}, 49 | {"SEQUENCE ", lib.Tag{}, false}, 50 | {"SEQUENCE CONSTRUCTED", lib.Tag{}, false}, 51 | } 52 | 53 | func TestDecodeTagString(t *testing.T) { 54 | for i, tt := range decodeTagStringTests { 55 | tag, err := decodeTagString(tt.input) 56 | if tag != tt.tag || (err == nil) != tt.ok { 57 | t.Errorf("%d. decodeTagString(%v) = %v, err=%s, wanted %v, success=%v", i, tt.input, tag, err, tt.tag, tt.ok) 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lib/tag_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The DER ASCII Authors. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package lib 16 | 17 | import "testing" 18 | 19 | var tagGetAliasTests = []struct { 20 | tag Tag 21 | name string 22 | toggleConstructed bool 23 | ok bool 24 | }{ 25 | {Tag{ClassUniversal, 16, true}, "SEQUENCE", false, true}, 26 | {Tag{ClassUniversal, 16, false}, "SEQUENCE", true, true}, 27 | {Tag{ClassUniversal, 2, true}, "INTEGER", true, true}, 28 | {Tag{ClassUniversal, 2, false}, "INTEGER", false, true}, 29 | {Tag{ClassApplication, 2, false}, "", false, false}, 30 | {Tag{ClassUniversal, 0, false}, "", false, false}, 31 | } 32 | 33 | func TestTagGetAlias(t *testing.T) { 34 | for i, tt := range tagGetAliasTests { 35 | name, toggleConstructed, ok := tt.tag.GetAlias() 36 | if !tt.ok { 37 | if ok { 38 | t.Errorf("%d. Unexpectedly found alias for %v.", i, tt.tag) 39 | } 40 | } else if !ok { 41 | t.Errorf("%d. Cound not find alias for %v.", i, tt.tag) 42 | } else if name != tt.name || toggleConstructed != tt.toggleConstructed { 43 | t.Errorf("%d. tag.GetAlias = %v, %v, wanted %v, %v.", i, name, toggleConstructed, tt.name, tt.toggleConstructed) 44 | } 45 | } 46 | } 47 | 48 | var tagByNameTests = []struct { 49 | name string 50 | tag Tag 51 | ok bool 52 | }{ 53 | {"BOGUS", Tag{}, false}, 54 | {"SEQUENCE", Tag{ClassUniversal, 16, true}, true}, 55 | {"INTEGER", Tag{ClassUniversal, 2, false}, true}, 56 | {"OCTET STRING", Tag{}, false}, 57 | {"OCTET_STRING", Tag{ClassUniversal, 4, false}, true}, 58 | } 59 | 60 | func TestTagByName(t *testing.T) { 61 | for i, tt := range tagByNameTests { 62 | tag, ok := TagByName(tt.name) 63 | if !tt.ok { 64 | if ok { 65 | t.Errorf("%d. Unexpectedly found tag named %v.", i, tt.name) 66 | } 67 | } else if !ok { 68 | t.Errorf("%d. Cound not find tag named %v.", i, tt.name) 69 | } else if tag != tt.tag { 70 | t.Errorf("%d. TagByName(%v) = %v, wanted %v.", i, tt.name, tag, tt.tag) 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /ascii2der/encoder.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The DER ASCII Authors. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import "github.com/google/der-ascii/lib" 18 | 19 | func appendBase128(dst []byte, value uint32) []byte { 20 | // Special-case: zero is encoded with one, not zero bytes. 21 | if value == 0 { 22 | return append(dst, 0) 23 | } 24 | // Count how many bytes are needed. 25 | var l int 26 | for n := value; n != 0; n >>= 7 { 27 | l++ 28 | } 29 | for ; l > 0; l-- { 30 | b := byte(value>>uint(7*(l-1))) & 0x7f 31 | if l > 1 { 32 | b |= 0x80 33 | } 34 | dst = append(dst, b) 35 | } 36 | return dst 37 | } 38 | 39 | // appendTag marshals the given tag and appends the result to dst, returning the 40 | // updated slice. 41 | func appendTag(dst []byte, tag lib.Tag) []byte { 42 | b := byte(tag.Class) 43 | if tag.Constructed { 44 | b |= 0x20 45 | } 46 | if tag.Number < 0x1f { 47 | // Low-tag-number form. 48 | b |= byte(tag.Number) 49 | return append(dst, b) 50 | } 51 | 52 | // High-tag-number form. 53 | b |= 0x1f 54 | dst = append(dst, b) 55 | return appendBase128(dst, tag.Number) 56 | } 57 | 58 | // appendLength marshals the given length in DER and appends the result to dst, 59 | // returning the updated slice. 60 | func appendLength(dst []byte, length int) []byte { 61 | if length < 0x80 { 62 | // Short-form length. 63 | return append(dst, byte(length)) 64 | } 65 | 66 | // Long-form length. Count how many bytes are needed. 67 | var l byte 68 | for n := length; n != 0; n >>= 8 { 69 | l++ 70 | } 71 | dst = append(dst, 0x80|l) 72 | for ; l > 0; l-- { 73 | dst = append(dst, byte(length>>uint(8*(l-1)))) 74 | } 75 | return dst 76 | } 77 | 78 | // appendInteger marshals the given value as the contents of a DER INTEGER and 79 | // appends the result to dst, returning the updated slice. 80 | func appendInteger(dst []byte, value int64) []byte { 81 | // Count how many bytes are needed. 82 | l := 1 83 | for n := value; n > 0x7f || n < (0x80-0x100); n >>= 8 { 84 | l++ 85 | } 86 | 87 | for ; l > 0; l-- { 88 | dst = append(dst, byte(value>>uint(8*(l-1)))) 89 | } 90 | return dst 91 | } 92 | 93 | func appendObjectIdentifier(dst []byte, value []uint32) ([]byte, bool) { 94 | // Validate the input before anything is written. 95 | if len(value) < 2 || value[0] > 2 || (value[0] < 2 && value[1] > 39) { 96 | return dst, false 97 | } 98 | if value[0]*40+value[1] < value[1] { 99 | return dst, false 100 | } 101 | 102 | dst = appendBase128(dst, value[0]*40+value[1]) 103 | for _, v := range value[2:] { 104 | dst = appendBase128(dst, v) 105 | } 106 | return dst, true 107 | } 108 | -------------------------------------------------------------------------------- /lib/tag.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The DER ASCII Authors. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // package lib contains common routines between der2ascii and ascii2der. 16 | package lib 17 | 18 | type Class byte 19 | 20 | const ( 21 | ClassUniversal Class = 0x0 22 | ClassApplication Class = 0x40 23 | ClassContextSpecific Class = 0x80 24 | ClassPrivate Class = 0xc0 25 | ) 26 | 27 | type Tag struct { 28 | Class Class 29 | Number uint32 30 | Constructed bool 31 | } 32 | 33 | // GetAlias looks up the alias for the given tag. If one exists, it returns the 34 | // name and sets toggleConstructed if the tag's constructed bit does not match 35 | // the alias's default. Otherwise it sets ok to false. 36 | func (t Tag) GetAlias() (name string, toggleConstructed bool, ok bool) { 37 | if t.Class != ClassUniversal { 38 | return 39 | } 40 | for _, u := range universalTags { 41 | if u.number == t.Number { 42 | name = u.name 43 | toggleConstructed = u.constructed != t.Constructed 44 | ok = true 45 | return 46 | } 47 | } 48 | return 49 | } 50 | 51 | var universalTags = []struct { 52 | number uint32 53 | name string 54 | constructed bool 55 | }{ 56 | // 0 is reserved. 57 | {1, "BOOLEAN", false}, 58 | {2, "INTEGER", false}, 59 | {3, "BIT_STRING", false}, 60 | {4, "OCTET_STRING", false}, 61 | {5, "NULL", false}, 62 | {6, "OBJECT_IDENTIFIER", false}, 63 | {7, "OBJECT_DESCRIPTOR", false}, 64 | {8, "EXTERNAL", false}, 65 | {9, "REAL", false}, 66 | {10, "ENUMERATED", false}, 67 | {12, "UTF8String", false}, 68 | {13, "EMBEDDED_PDV", false}, 69 | {14, "TIME", false}, 70 | // 15 is reserved for future expansion. 71 | {16, "SEQUENCE", true}, 72 | {17, "SET", true}, 73 | {18, "NumericString", false}, 74 | {19, "PrintableString", false}, 75 | {20, "T61String", false}, 76 | {21, "VideotexString", false}, 77 | {22, "IA5String", false}, 78 | {23, "UTCTime", false}, 79 | {24, "GeneralizedTime", false}, 80 | {25, "GraphicString", false}, 81 | {26, "VisibleString", false}, 82 | {27, "GeneralString", false}, 83 | {28, "UniversalString", false}, 84 | {30, "BMPString", false}, 85 | {31, "DATE", false}, 86 | {32, "TIME-OF-DAY", false}, 87 | {33, "DATE-TIME", false}, 88 | {34, "DURATION", false}, 89 | {35, "OID-IRI", false}, 90 | {36, "RELATIVE-OID-IRI", false}, 91 | } 92 | 93 | // TagByName returns the universal tag by name or false if no tag matches. 94 | func TagByName(name string) (Tag, bool) { 95 | for _, u := range universalTags { 96 | if u.name == name { 97 | return Tag{ClassUniversal, u.number, u.constructed}, true 98 | } 99 | } 100 | return Tag{}, false 101 | } 102 | -------------------------------------------------------------------------------- /ascii2der/encoder_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The DER ASCII Authors. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "bytes" 19 | "math" 20 | "testing" 21 | 22 | "github.com/google/der-ascii/lib" 23 | ) 24 | 25 | var appendTagTests = []struct { 26 | tag lib.Tag 27 | encoded []byte 28 | }{ 29 | {lib.Tag{lib.ClassUniversal, 16, true}, []byte{0x30}}, 30 | {lib.Tag{lib.ClassUniversal, 2, false}, []byte{0x02}}, 31 | {lib.Tag{lib.ClassContextSpecific, 1, true}, []byte{0xa1}}, 32 | {lib.Tag{lib.ClassApplication, 1234, true}, []byte{0x7f, 0x89, 0x52}}, 33 | } 34 | 35 | func TestAppendTag(t *testing.T) { 36 | for i, tt := range appendTagTests { 37 | dst := appendTag(nil, tt.tag) 38 | if !bytes.Equal(dst, tt.encoded) { 39 | t.Errorf("%d. appendTag(nil, %v) = %v, wanted %v.", i, tt.tag, dst, tt.encoded) 40 | } 41 | 42 | dst = appendTag(dst, tt.tag) 43 | if l := len(tt.encoded); len(dst) != l*2 || !bytes.Equal(dst[:l], tt.encoded) || !bytes.Equal(dst[l:], tt.encoded) { 44 | t.Errorf("%d. appendTag did not preserve existing contents.", i) 45 | } 46 | } 47 | } 48 | 49 | var appendLengthTests = []struct { 50 | length int 51 | encoded []byte 52 | }{ 53 | {0, []byte{0}}, 54 | {5, []byte{0x05}}, 55 | {0x1f, []byte{0x1f}}, 56 | {0x80, []byte{0x81, 0x80}}, 57 | {0xff, []byte{0x81, 0xff}}, 58 | {0x100, []byte{0x82, 0x01, 0x00}}, 59 | {0xffffff, []byte{0x83, 0xff, 0xff, 0xff}}, 60 | } 61 | 62 | func TestAppendLength(t *testing.T) { 63 | for i, tt := range appendLengthTests { 64 | dst := appendLength(nil, tt.length) 65 | if !bytes.Equal(dst, tt.encoded) { 66 | t.Errorf("%d. appendLength(nil, %v) = %v, wanted %v.", i, tt.length, dst, tt.encoded) 67 | } 68 | 69 | dst = appendLength(dst, tt.length) 70 | if l := len(tt.encoded); len(dst) != l*2 || !bytes.Equal(dst[:l], tt.encoded) || !bytes.Equal(dst[l:], tt.encoded) { 71 | t.Errorf("%d. appendLength did not preserve existing contents.", i) 72 | } 73 | } 74 | } 75 | 76 | var appendIntegerTests = []struct { 77 | value int64 78 | encoded []byte 79 | }{ 80 | {0, []byte{0}}, 81 | {1, []byte{1}}, 82 | {-1, []byte{0xff}}, 83 | {127, []byte{0x7f}}, 84 | {128, []byte{0x00, 0x80}}, 85 | {0x12345678, []byte{0x12, 0x34, 0x56, 0x78}}, 86 | {-127, []byte{0x81}}, 87 | {-128, []byte{0x80}}, 88 | {-129, []byte{0xff, 0x7f}}, 89 | } 90 | 91 | func TestAppendInteger(t *testing.T) { 92 | for i, tt := range appendIntegerTests { 93 | dst := appendInteger(nil, tt.value) 94 | if !bytes.Equal(dst, tt.encoded) { 95 | t.Errorf("%d. appendInteger(nil, %v) = %v, wanted %v.", i, tt.value, dst, tt.encoded) 96 | } 97 | 98 | dst = appendInteger(dst, tt.value) 99 | if l := len(tt.encoded); len(dst) != l*2 || !bytes.Equal(dst[:l], tt.encoded) || !bytes.Equal(dst[l:], tt.encoded) { 100 | t.Errorf("%d. appendInteger did not preserve existing contents.", i) 101 | } 102 | } 103 | } 104 | 105 | var appendObjectIdentifierTests = []struct { 106 | value []uint32 107 | encoded []byte 108 | ok bool 109 | }{ 110 | {[]uint32{0, 1}, []byte{1}, true}, 111 | {[]uint32{1, 2, 3, 4, 0, 127, 128, 129}, []byte{42, 3, 4, 0, 0x7f, 0x81, 0x00, 0x81, 0x01}, true}, 112 | {[]uint32{2, 1}, []byte{81}, true}, 113 | {[]uint32{2, math.MaxUint32 - 80}, []byte{0x8f, 0xff, 0xff, 0xff, 0x7f}, true}, 114 | // Invalid OIDs. 115 | {[]uint32{}, nil, false}, 116 | {[]uint32{1}, nil, false}, 117 | {[]uint32{1, 40}, nil, false}, 118 | {[]uint32{0, 40}, nil, false}, 119 | {[]uint32{3, 1}, nil, false}, 120 | {[]uint32{2, math.MaxUint32 - 79}, nil, false}, 121 | } 122 | 123 | func TestAppendObjectIdentifier(t *testing.T) { 124 | for i, tt := range appendObjectIdentifierTests { 125 | dst, ok := appendObjectIdentifier(nil, tt.value) 126 | if !tt.ok { 127 | if ok { 128 | t.Errorf("%d. appendObjectIdentifier(nil, %v) unexpectedly suceeded.", i, tt.value) 129 | } else if len(dst) != 0 { 130 | t.Errorf("%d. appendObjectIdentifier did not preserve input.", i) 131 | } 132 | } else if !bytes.Equal(dst, tt.encoded) { 133 | t.Errorf("%d. appendObjectIdentifier(nil, %v) = %v, wanted %v.", i, tt.value, dst, tt.encoded) 134 | } 135 | 136 | dst = []byte{0} 137 | dst, ok = appendObjectIdentifier(dst, tt.value) 138 | if !tt.ok { 139 | if ok { 140 | t.Errorf("%d. appendObjectIdentifier(nil, %v) unexpectedly suceeded.", i, tt.value) 141 | } else if !bytes.Equal(dst, []byte{0}) { 142 | t.Errorf("%d. appendObjectIdentifier did not preserve input.", i) 143 | } 144 | } else if l := len(tt.encoded); len(dst) != l+1 || dst[0] != 0 || !bytes.Equal(dst[1:], tt.encoded) { 145 | t.Errorf("%d. appendObjectIdentifier did not preserve existing contents.", i) 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /ascii2der/scanner_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The DER ASCII Authors. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "bytes" 19 | "testing" 20 | ) 21 | 22 | func tokenToString(kind tokenKind) string { 23 | switch kind { 24 | case tokenBytes: 25 | return "bytes" 26 | case tokenLeftCurly: 27 | return "left-curly" 28 | case tokenRightCurly: 29 | return "right-curly" 30 | case tokenEOF: 31 | return "EOF" 32 | default: 33 | panic(kind) 34 | } 35 | } 36 | 37 | var scannerTests = []struct { 38 | in string 39 | tokens []token 40 | ok bool 41 | }{ 42 | { 43 | `# First, the basic kinds of tokens. 44 | SEQUENCE [SEQUENCE] 1 -1 1.2.3.4 ` + "`aabbcc`" + ` "hello" { } 45 | 46 | # Tokens can be bunched up together. 47 | SEQUENCE[0]{}SEQUENCE}1}-1}1.2}#comment 48 | 49 | # Each of these is legal whitespace. 50 | ` + "\t\r\n " + ` 51 | 52 | # Escape sequences. 53 | "\"\n\x42\\" 54 | 55 | # Uppercase hex is fine too. 56 | ` + "`AABBCC`", 57 | []token{ 58 | {Kind: tokenBytes, Value: []byte{0x30}}, 59 | {Kind: tokenBytes, Value: []byte{0x30}}, 60 | {Kind: tokenBytes, Value: []byte{0x01}}, 61 | {Kind: tokenBytes, Value: []byte{0xff}}, 62 | {Kind: tokenBytes, Value: []byte{42, 3, 4}}, 63 | {Kind: tokenBytes, Value: []byte{0xaa, 0xbb, 0xcc}}, 64 | {Kind: tokenBytes, Value: []byte("hello")}, 65 | {Kind: tokenLeftCurly}, 66 | {Kind: tokenRightCurly}, 67 | {Kind: tokenBytes, Value: []byte{0x30}}, 68 | {Kind: tokenBytes, Value: []byte{0xa0}}, 69 | {Kind: tokenLeftCurly}, 70 | {Kind: tokenRightCurly}, 71 | {Kind: tokenBytes, Value: []byte{0x30}}, 72 | {Kind: tokenRightCurly}, 73 | {Kind: tokenBytes, Value: []byte{0x01}}, 74 | {Kind: tokenRightCurly}, 75 | {Kind: tokenBytes, Value: []byte{0xff}}, 76 | {Kind: tokenRightCurly}, 77 | {Kind: tokenBytes, Value: []byte{42}}, 78 | {Kind: tokenRightCurly}, 79 | {Kind: tokenBytes, Value: []byte{'"', '\n', 0x42, '\\'}}, 80 | {Kind: tokenBytes, Value: []byte{0xaa, 0xbb, 0xcc}}, 81 | {Kind: tokenEOF}, 82 | }, 83 | true, 84 | }, 85 | // Garbage tokens. 86 | {"SEQUENC", nil, false}, 87 | {"1...2", nil, false}, 88 | // Unmatched [. 89 | {"[SEQUENCE", nil, false}, 90 | // Unmatched ". 91 | {`"`, nil, false}, 92 | // Unmatched `. 93 | {"`", nil, false}, 94 | // Integer overflow. 95 | {"999999999999999999999999999999999999999999999999999999999999999", nil, false}, 96 | // Invalid OID. 97 | {"1.99.1", nil, false}, 98 | // OID component overflow. 99 | {"1.1.99999999999999999999999999999999999999999999999999999999999999999", nil, false}, 100 | // Bad tag string. 101 | {"[THIS IS NOT A VALID TAG]", nil, false}, 102 | // Bad hex bytes. 103 | {"`hi there!`", nil, false}, 104 | // Bad or truncated escape sequences. 105 | {`"\`, nil, false}, 106 | {`"\x`, nil, false}, 107 | {`"\x1`, nil, false}, 108 | {`"\x??"`, nil, false}, 109 | {`"\?"`, nil, false}, 110 | // Tokenization works up to a syntax error. 111 | {`"hello" "world`, []token{{Kind: tokenBytes, Value: []byte("hello")}}, false}, 112 | } 113 | 114 | func scanAll(in string) (tokens []token, ok bool) { 115 | scanner := newScanner(in) 116 | for { 117 | token, err := scanner.Next() 118 | if err != nil { 119 | return 120 | } 121 | tokens = append(tokens, token) 122 | if token.Kind == tokenEOF { 123 | ok = true 124 | return 125 | } 126 | } 127 | } 128 | 129 | func TestScanner(t *testing.T) { 130 | for i, tt := range scannerTests { 131 | tokens, ok := scanAll(tt.in) 132 | if len(tokens) != len(tt.tokens) { 133 | t.Errorf("%d. output length mismatch. Got %v, wanted %v.", i, len(tokens), len(tt.tokens)) 134 | } 135 | 136 | for j := 0; j < len(tokens) && j < len(tt.tokens); j++ { 137 | if tokens[j].Kind != tt.tokens[j].Kind { 138 | t.Errorf("%d. token %d was %s, wanted %s.", i, j, tokenToString(tokens[j].Kind), tokenToString(tt.tokens[j].Kind)) 139 | } else if tokens[j].Kind == tokenBytes && !bytes.Equal(tokens[j].Value, tt.tokens[j].Value) { 140 | t.Errorf("%d. token %d had value %x, wanted %x.", i, j, tokens[j].Value, tt.tokens[j].Value) 141 | } 142 | } 143 | 144 | if ok != tt.ok { 145 | t.Errorf("%d. success did not match. Got %v, wanted %v.", i, ok, tt.ok) 146 | } 147 | } 148 | } 149 | 150 | var asciiToDERTests = []struct { 151 | in string 152 | out []byte 153 | ok bool 154 | }{ 155 | {"SEQUENCE { INTEGER { 42 } INTEGER { 1 } }", []byte{0x30, 0x06, 0x02, 0x01, 0x2a, 0x02, 0x01, 0x01}, true}, 156 | // Mismatched curlies. 157 | {"{", nil, false}, 158 | {"}", nil, false}, 159 | // Invalid token. 160 | {"BOGUS", nil, false}, 161 | } 162 | 163 | func TestASCIIToDER(t *testing.T) { 164 | for i, tt := range asciiToDERTests { 165 | out, err := asciiToDER(tt.in) 166 | ok := err == nil 167 | if !tt.ok { 168 | if ok { 169 | t.Errorf("%d. asciiToDER(%v) unexpectedly succeeded.", i, tt.in) 170 | } 171 | } else { 172 | if !ok { 173 | t.Errorf("%d. asciiToDER(%v) unexpectedly failed.", i, tt.in) 174 | } else if !bytes.Equal(out, tt.out) { 175 | t.Errorf("%d. asciiToDER(%v) = %x wanted %x.", i, tt.in, out, tt.out) 176 | } 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /der2ascii/decoder.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The DER ASCII Authors. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import "github.com/google/der-ascii/lib" 18 | 19 | func parseBase128(bytes []byte) (ret uint32, rest []byte, ok bool) { 20 | // The tag must be minimally-encoded, so the first byte may not be 0x80. 21 | if len(bytes) == 0 || bytes[0] == 0x80 { 22 | return 0, bytes, false 23 | } 24 | 25 | for { 26 | if len(bytes) == 0 || (ret<<7)>>7 != ret { 27 | // Input too small or overflow. 28 | return 0, bytes, false 29 | } 30 | b := bytes[0] 31 | ret <<= 7 32 | ret |= uint32(b & 0x7f) 33 | bytes = bytes[1:] 34 | if b&0x80 == 0 { 35 | return ret, bytes, true 36 | } 37 | } 38 | } 39 | 40 | // parseTag parses a tag from b, returning the resulting tag and the remainder 41 | // of the slice. On parse failure, ok is returned as false and rest is 42 | // unchanged. 43 | func parseTag(bytes []byte) (tag lib.Tag, rest []byte, ok bool) { 44 | rest = bytes 45 | 46 | // Consume the first byte. Reject EOC. 47 | if len(rest) == 0 || rest[0] == 0 { 48 | return 49 | } 50 | b := rest[0] 51 | rest = rest[1:] 52 | 53 | class := lib.Class(b & 0xc0) 54 | number := uint32(b & 0x1f) 55 | constructed := b&0x20 != 0 56 | if number < 0x1f { 57 | // Low-tag-number form. 58 | tag = lib.Tag{class, number, constructed} 59 | ok = true 60 | return 61 | } 62 | 63 | n, rest, base128Ok := parseBase128(rest) 64 | if !base128Ok || n < 0x1f { 65 | // Parse error or non-minimal encoding. 66 | rest = bytes 67 | return 68 | } 69 | number = n 70 | 71 | tag = lib.Tag{class, number, constructed} 72 | ok = true 73 | return 74 | } 75 | 76 | // parseTagAndLength parses a tag and length pair from bytes. If the resulting 77 | // length is indefinite, it sets indefinite to true. 78 | func parseTagAndLength(bytes []byte) (tag lib.Tag, length int, indefinite bool, rest []byte, ok bool) { 79 | rest = bytes 80 | 81 | // Parse the tag. 82 | tag, rest, ok = parseTag(rest) 83 | if !ok { 84 | return lib.Tag{}, 0, false, bytes, false 85 | } 86 | 87 | // Parse the length. 88 | if len(rest) == 0 { 89 | return lib.Tag{}, 0, false, bytes, false 90 | } 91 | b := rest[0] 92 | rest = rest[1:] 93 | if b < 0x80 { 94 | // Short form length. 95 | length = int(b) 96 | return 97 | } 98 | if b == 0x80 { 99 | // Indefinite-length. Must be constructed. 100 | if !tag.Constructed { 101 | return lib.Tag{}, 0, false, bytes, false 102 | } 103 | indefinite = true 104 | return 105 | } 106 | // Long form length. 107 | b &= 0x7f 108 | if int(b) > len(rest) || rest[0] == 0 { 109 | // Not enough room or non-minimal length. 110 | return lib.Tag{}, 0, false, bytes, false 111 | } 112 | for i := 0; i < int(b); i++ { 113 | if length >= 1<<23 { 114 | // Overflow. 115 | return lib.Tag{}, 0, false, bytes, false 116 | } 117 | length <<= 8 118 | length |= int(rest[i]) 119 | } 120 | if length < 0x80 { 121 | // Should have been short form. 122 | return lib.Tag{}, 0, false, bytes, false 123 | } 124 | rest = rest[b:] 125 | return 126 | } 127 | 128 | // parseElement parses an element from bytes. If the element is 129 | // indefinite-length body is left as nil and instead indefinite is set to true. 130 | func parseElement(bytes []byte) (tag lib.Tag, body []byte, indefinite bool, rest []byte, ok bool) { 131 | rest = bytes 132 | 133 | tag, length, indefinite, rest, ok := parseTagAndLength(rest) 134 | if !ok || length > len(rest) { 135 | return lib.Tag{}, nil, false, bytes, false 136 | } 137 | 138 | body = rest[:length] 139 | rest = rest[length:] 140 | return 141 | } 142 | 143 | // decodeInteger decodes bytes as the contents of a DER INTEGER. It returns the 144 | // value on success and false otherwise. 145 | func decodeInteger(bytes []byte) (int64, bool) { 146 | if len(bytes) == 0 { 147 | return 0, false 148 | } 149 | 150 | // Reject non-minimal encodings. 151 | if len(bytes) > 1 && (bytes[0] == 0 || bytes[0] == 0xff) && bytes[0]&0x80 == bytes[1]&0x80 { 152 | return 0, false 153 | } 154 | 155 | val := int64(bytes[0]) 156 | if val&0x80 != 0 { 157 | val -= 256 158 | } 159 | for _, v := range bytes[1:] { 160 | if (val<<8)>>8 != val { 161 | return 0, false 162 | } 163 | val <<= 8 164 | val |= int64(v) 165 | } 166 | return val, true 167 | } 168 | 169 | // decodeInteger decodes bytes as the contents of a DER OBJECT IDENTIFIER. It 170 | // returns the value on success and false otherwise. 171 | func decodeObjectIdentifier(bytes []byte) (oid []uint32, ok bool) { 172 | // Reserve a space as the first component is split. 173 | oid = []uint32{0} 174 | 175 | // Decode each component. 176 | for len(bytes) != 0 { 177 | var c uint32 178 | c, bytes, ok = parseBase128(bytes) 179 | if !ok { 180 | return nil, false 181 | } 182 | oid = append(oid, c) 183 | } 184 | 185 | // OIDs must have at least two components. 186 | if len(oid) < 2 { 187 | return nil, false 188 | } 189 | 190 | // Adjust the first component. 191 | if oid[1] >= 80 { 192 | oid[0] = 2 193 | oid[1] -= 80 194 | } else if oid[1] >= 40 { 195 | oid[0] = 1 196 | oid[1] -= 40 197 | } 198 | 199 | return oid, true 200 | } 201 | -------------------------------------------------------------------------------- /der2ascii/writer_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The DER ASCII Authors. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "testing" 19 | 20 | "github.com/google/der-ascii/lib" 21 | ) 22 | 23 | func TestWriter(t *testing.T) { 24 | var w writer 25 | 26 | w.WriteLine("hello") 27 | w.AddIndent(1) 28 | w.WriteLine("world") 29 | w.AddIndent(-1) 30 | w.WriteLine("1") 31 | w.AddIndent(1) 32 | if indent := w.Indent(); indent != 1 { 33 | t.Errorf("w.Indent() = %d, wanted 1.", indent) 34 | } 35 | w.SetIndent(3) 36 | w.WriteLine("2") 37 | 38 | const expected = `hello 39 | world 40 | 1 41 | 2 42 | ` 43 | if out := w.String(); out != expected { 44 | t.Errorf("w.String = `%s`, wanted `%s`.", out, expected) 45 | } 46 | } 47 | 48 | var isMadeOfElementsTests = []struct { 49 | in []byte 50 | out bool 51 | }{ 52 | {[]byte{}, true}, 53 | {[]byte{0x00, 0x00}, false}, 54 | {[]byte{0x30, 0x00, 0x02, 0x01, 0x01}, true}, 55 | {[]byte{0x30, 0x80, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01, 0x00, 0x00}, true}, 56 | {[]byte{0x30, 0x80, 0x02, 0x01, 0x01, 0x02, 0x01, 0x01}, false}, 57 | } 58 | 59 | func TestIsMadeOfElements(t *testing.T) { 60 | for i, tt := range isMadeOfElementsTests { 61 | if out := isMadeOfElements(tt.in); out != tt.out { 62 | t.Errorf("%d. isMadeOfElements(%v) = %v, want %v.", i, tt.in, out, tt.out) 63 | } 64 | } 65 | } 66 | 67 | var tagToStringTests = []struct { 68 | in lib.Tag 69 | out string 70 | }{ 71 | {lib.Tag{lib.ClassUniversal, 16, true}, "SEQUENCE"}, 72 | {lib.Tag{lib.ClassUniversal, 16, false}, "[SEQUENCE PRIMITIVE]"}, 73 | {lib.Tag{lib.ClassUniversal, 2, true}, "[INTEGER CONSTRUCTED]"}, 74 | {lib.Tag{lib.ClassUniversal, 2, false}, "INTEGER"}, 75 | {lib.Tag{lib.ClassUniversal, 1234, true}, "[UNIVERSAL 1234]"}, 76 | {lib.Tag{lib.ClassContextSpecific, 0, true}, "[0]"}, 77 | {lib.Tag{lib.ClassContextSpecific, 0, false}, "[0 PRIMITIVE]"}, 78 | {lib.Tag{lib.ClassApplication, 0, true}, "[APPLICATION 0]"}, 79 | {lib.Tag{lib.ClassApplication, 0, false}, "[APPLICATION 0 PRIMITIVE]"}, 80 | {lib.Tag{lib.ClassPrivate, 0, true}, "[PRIVATE 0]"}, 81 | {lib.Tag{lib.ClassPrivate, 0, false}, "[PRIVATE 0 PRIMITIVE]"}, 82 | } 83 | 84 | func TestTagToString(t *testing.T) { 85 | for i, tt := range tagToStringTests { 86 | if out := tagToString(tt.in); out != tt.out { 87 | t.Errorf("%d. tagToString(%v) = %v, want %v.", i, tt.in, out, tt.out) 88 | } 89 | } 90 | 91 | } 92 | 93 | type convertFuncTest struct { 94 | in []byte 95 | out string 96 | } 97 | 98 | func testConvertFunc(t *testing.T, name string, convertFunc func(in []byte) string, tests []convertFuncTest) { 99 | for i, tt := range tests { 100 | if out := convertFunc(tt.in); out != tt.out { 101 | t.Errorf("%d. %s(%v) = %v, want %v.", i, name, tt.in, out, tt.out) 102 | } 103 | } 104 | } 105 | 106 | var bytesToStringTests = []convertFuncTest{ 107 | // Empty strings are empty. 108 | {nil, ""}, 109 | // Mostly-ASCII strings are encoded in ASCII. 110 | {[]byte("hello\nworld\n\xff\"\\"), `"hello\nworld\n\xff\"\\"`}, 111 | // Otherwise, encoded in hex. 112 | {[]byte{0x01, 0x02, 0x03, 0x04, 0x05}, "`0102030405`"}, 113 | } 114 | 115 | func TestBytesToString(t *testing.T) { 116 | testConvertFunc(t, "bytesToString", bytesToString, bytesToStringTests) 117 | } 118 | 119 | var integerToStringTests = []convertFuncTest{ 120 | // Valid and reasonably-sized integers are encoded as integers. 121 | {[]byte{42}, "42"}, 122 | {[]byte{0xff}, "-1"}, 123 | // Overly large integers are encoded in hex. 124 | {[]byte{0xff, 0xff, 0xff, 0xff}, "`ffffffff`"}, 125 | {[]byte{0x00, 0xff, 0xff, 0xff, 0xff}, "`00ffffffff`"}, 126 | // Invalid (non-minimal) integers are encoded in hex. 127 | {[]byte{0x00, 0x00}, "`0000`"}, 128 | } 129 | 130 | func TestIntegerToString(t *testing.T) { 131 | testConvertFunc(t, "integerToString", integerToString, integerToStringTests) 132 | } 133 | 134 | var objectIdentifierToStringTests = []convertFuncTest{ 135 | // Prefer to encode OIDs as OIDs. 136 | {[]byte{42, 3, 4, 5}, "1.2.3.4.5"}, 137 | // Invalid OIDs are encoded in hex. 138 | {[]byte{0x80, 0x00}, "`8000`"}, 139 | } 140 | 141 | func TestObjectIdentifierToString(t *testing.T) { 142 | testConvertFunc(t, "objectIdentifierToString", objectIdentifierToString, objectIdentifierToStringTests) 143 | } 144 | 145 | var derToASCIITests = []convertFuncTest{ 146 | // Sample input that tests various difficult cases. 147 | { 148 | []byte{0x30, 0x07, 0x67, 0x61, 0x72, 0x62, 0x61, 0x67, 0x65, 0x04, 0x0a, 0xa0, 0x80, 0x02, 0x01, 0x01, 0x02, 0x01, 0xff, 0x00, 0x00, 0x04, 0x0b, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64, 0x30, 0x16, 0xa0, 0x80, 0x02, 0x01, 0x01, 0x02, 0x02, 0x00, 0x00, 0x30, 0x80, 0x05, 0x00, 0x06, 0x03, 0x2a, 0x03, 0x04, 0x06, 0x02, 0x80, 0x00, 0x03, 0x03, 0x00, 0x30, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x05, 0x01, 0x30, 0x80, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff}, 149 | `SEQUENCE { 150 | "garbage" 151 | } 152 | OCTET_STRING { 153 | [0] ` + "`80`" + ` 154 | INTEGER { 1 } 155 | INTEGER { -1 } 156 | ` + "`0000`" + ` 157 | } 158 | OCTET_STRING { "hello world" } 159 | SEQUENCE { 160 | [0] ` + "`80`" + ` 161 | INTEGER { 1 } 162 | INTEGER { ` + "`0000`" + ` } 163 | SEQUENCE ` + "`80`" + ` 164 | NULL {} 165 | OBJECT_IDENTIFIER { 1.2.3.4 } 166 | OBJECT_IDENTIFIER { ` + "`8000`" + ` } 167 | } 168 | BIT_STRING { 169 | ` + "`00`" + ` 170 | SEQUENCE {} 171 | } 172 | BIT_STRING { ` + "`000000`" + ` } 173 | BIT_STRING { ` + "`0130800000`" + ` } 174 | ` + "`ffffffff`" + ` 175 | `, 176 | }, 177 | } 178 | 179 | func TestDERToASCII(t *testing.T) { 180 | testConvertFunc(t, "derToASCII", derToASCII, derToASCIITests) 181 | } 182 | -------------------------------------------------------------------------------- /language.txt: -------------------------------------------------------------------------------- 1 | # DER ASCII Language Specification. 2 | 3 | # This specification is a valid DER ASCII file. 4 | 5 | 6 | # A DER ASCII file is a sequence of tokens. Most tokens are byte tokens and 7 | # resolve to a byte string which is emitted as soon as it is processed. 8 | 9 | # Tokens are separated by whitespace, which is defined to be space (0x20), TAB 10 | # (0x09), CR (0x0d), and LF (0x0a). Apart from acting as a token separator, 11 | # whitespace is not significant. 12 | 13 | # Comments begin with # and run to the end of the line. Comments are treated as 14 | # whitespace. 15 | 16 | 17 | # Quoted strings. 18 | 19 | "Quoted strings are delimited by double quotes. Backslash denotes escape 20 | sequences. Legal escape sequences are: \\ \" \x00 \n. \x00 consumes two hex 21 | digits and emits a byte. Otherwise, any byte before the closing quote, including 22 | newlines, is emitted as-is." 23 | 24 | # Objects in the file are emitted one after another, so: 25 | "hello world" 26 | # produces the same output as: 27 | "hello " "world" 28 | 29 | 30 | # Hex literals. 31 | 32 | # Backticks denote hex literals. Either uppercase or lowercase is legal, but no 33 | # characters other than hexadecimal digits may appear. A hex literal emits the 34 | # decoded byte string. 35 | `00` 36 | `abcdef` 37 | `AbCdEf` 38 | 39 | 40 | # Integers. 41 | 42 | # Tokens which match /-?[0-9]+/ are integer tokens. They emit the contents of 43 | # that integer's encoding as a DER INTEGER. (Big-endian, base-256, 44 | # two's-complement, and minimally-encoded.) 45 | 456 46 | 47 | 48 | # OIDs. 49 | 50 | # Tokens which match /[0-9]+(\.[0-9]+)+/ are OID tokens. They emits the contents 51 | # of that OID's encoding as a DER OBJECT IDENTIFIER. 52 | 1.2.840.113554.4.1.72585 53 | 54 | 55 | # Tag expressions. 56 | 57 | # Square brackets denote a tag expression, as in ASN.1. Unlike ASN.1, the 58 | # constructed bit is treated as part of the tag. 59 | # 60 | # A tag expression contains one to three components separated by space. The 61 | # components are an optional tag class, a decimal tag number, and an optional 62 | # constructed bit. By default, tags have class context-specific and set the 63 | # constructed bit. Alternatively, the first two components may be replaced by a 64 | # type name (see below). 65 | # 66 | # A tag expression emits the DER encoding of that tag. Note that it does not 67 | # emit an element body. Those are specified separatedly. 68 | # 69 | # Examples: 70 | [0] 71 | [0 PRIMITIVE] 72 | [0 CONSTRUCTED] # This is equivalent to [0] 73 | [APPLICATION 1] 74 | [PRIVATE 2] 75 | [UNIVERSAL 16] # This is a SEQUENCE. 76 | [UNIVERSAL 2 PRIMITIVE] # This is an INTEGER. 77 | 78 | # As a shorthand, one may write type names from ASN.1, replacing spaces with 79 | # underscore. These specify tag, number, and the constructed bit. The 80 | # constructed bit is set for SEQUENCE and SET and unset otherwise. 81 | INTEGER 82 | SEQUENCE 83 | OCTET_STRING 84 | 85 | # Within a tag expression, type names may also be used in place of the class 86 | # and tag number. This also switches the default constructed bit to that tag's 87 | # constructed bit. 88 | [SEQUENCE PRIMITIVE] 89 | [OCTET_STRING CONSTRUCTED] 90 | [INTEGER] # This is the same as INTEGER 91 | [INTEGER PRIMITIVE] # This is the same as INTEGER 92 | 93 | 94 | # Length prefixes. 95 | 96 | # Matching curly braces denote length prefixes. They emit a DER-encoded length 97 | # prefix followed by the encoding of the brace contents. There is no requirement 98 | # that braces correspond to tags, but non-garbage outputs should pair them up. 99 | 100 | # This is an OID. 101 | OBJECT_IDENTIFIER { 1.2.840.113554.4.1.72585 } 102 | 103 | # This is a NULL. 104 | NULL {} 105 | 106 | # This is a SEQUENCE of two INTEGERs. 107 | SEQUENCE { 108 | INTEGER { 1 } 109 | INTEGER { `00ff` } 110 | } 111 | 112 | # This is an explicitly-tagged SEQUENCE. 113 | [0] { 114 | SEQUENCE { 115 | INTEGER { 1 } 116 | INTEGER { `00ff` } 117 | } 118 | } 119 | 120 | # Note that curly braces are not optional, even in explicit tagging. Thus this 121 | # isn't the same thing, despite the similar ASN.1 syntax. 122 | [0] SEQUENCE { 123 | INTEGER { 1 } 124 | INTEGER { `00ff` } 125 | } 126 | 127 | # This is a BER constructed OCTET STRING. 128 | [OCTET_STRING CONSTRUCTED] { 129 | OCTET_STRING { "hello " } 130 | OCTET_STRING { "world" } 131 | } 132 | 133 | # Implicit tagging is written without the underlying tag, as in DER. This is an 134 | # implicitly-tagged INTEGER. Note that the constructed bit must be set 135 | # accordingly for a correct encoding. 136 | [0 PRIMITIVE] { 1 } 137 | 138 | 139 | # Examples. 140 | 141 | # These primitives may be combined with raw byte strings to produce other 142 | # encodings. 143 | 144 | # This is an indefinite-length SEQUENCE. 145 | SEQUENCE `80` 146 | INTEGER { 1 } 147 | INTEGER { 2 } 148 | `0000` 149 | 150 | # This is a SEQUENCE with the wrong constructed bit. 151 | [SEQUENCE PRIMITIVE] { 152 | INTEGER { 1 } 153 | INTEGER { 2 } 154 | } 155 | 156 | # This is a SEQUENCE with the tag incorrectly encoded in high tag number form. 157 | `3f90` { 158 | INTEGER { 1 } 159 | INTEGER { 2 } 160 | } 161 | 162 | # This is a SEQUENCE with garbage instead of the length. 163 | SEQUENCE `aabbcc` 164 | INTEGER { 1 } 165 | INTEGER { 2 } 166 | 167 | 168 | # Disassembler. 169 | 170 | # Although the conversion from DER ASCII to a byte string is well-defined, the 171 | # inverse is not. A given byte string may have multiple disassemblies. The 172 | # disassembler heuristically attempts to give a useful conversion for its 173 | # input. 174 | # 175 | # It is a goal that any valid BER or DER input will be decoded reasonably, along 176 | # with common embeddings of encoded structures within OCTET STRINGs, etc. 177 | # Invalid encodings, however, will likely disassemble to a hex literal and not 178 | # be easily editable. 179 | # 180 | # The algorithm is as follows: 181 | # 182 | # 1. Raw byte strings are encoded heuristically as quoted strings or hex 183 | # literals depending on what fraction is printable ASCII. 184 | # 185 | # 2. Greedly parse BER elements out of the input. Indefinite-length encoding is 186 | # legal. On parse error, encode the remaining bytes as in step 1. 187 | # 188 | # 3. Minimally encode the tag in the BER element followed by the body in curly 189 | # braces. If the element is indefinite-length, emit `80` for { and `0000` for 190 | # }. 191 | # 192 | # 4. If the element has the constructed bit, recurse to encode the body. 193 | # 194 | # 5. Otherwise, heuristically encode the body based on the tag: 195 | # 196 | # a. If the tag is INTEGER and the body is a valid integer under some 197 | # threshold, encode as an integer. Otherwise a hex literal. 198 | # 199 | # b. If the tag is OBJECT IDENTIFIER and the body is a valid OID, encode as 200 | # an OID. Otherwise a hex literal. 201 | # 202 | # c. If the tag is BIT STRING, the body's first byte is 00 and the remainder 203 | # may be parsed as a series of BER elements without trailing data, emit 204 | # `00` and recurse into the remainder of the body. Otherwise, emit the 205 | # body as a raw byte string. This is to account for X.509 incorrectly 206 | # using BIT STRING instead of OCTET STRING for SubjectPublicKeyInfo and 207 | # signatures. 208 | # 209 | # d. Otherwise, if the body may be parsed as a series of BER elements without 210 | # trailing data, recurse into the body. If not, encode it as a raw byte 211 | # string. 212 | -------------------------------------------------------------------------------- /ascii2der/scanner.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The DER ASCII Authors. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "encoding/hex" 19 | "errors" 20 | "fmt" 21 | "regexp" 22 | "strconv" 23 | "strings" 24 | 25 | "github.com/google/der-ascii/lib" 26 | ) 27 | 28 | // A position describes a location in the input stream. 29 | type position struct { 30 | Offset int // offset, starting at 0 31 | Line int // line number, starting at 1 32 | Column int // column number, starting at 1 (byte count) 33 | } 34 | 35 | // A tokenKind is a kind of token. 36 | type tokenKind int 37 | 38 | const ( 39 | tokenBytes tokenKind = iota 40 | tokenLeftCurly 41 | tokenRightCurly 42 | tokenEOF 43 | ) 44 | 45 | // A parseError is an error during parsing DER ASCII. 46 | type parseError struct { 47 | Pos position 48 | Err error 49 | } 50 | 51 | func (t *parseError) Error() string { 52 | return fmt.Sprintf("line %d: %s", t.Pos.Line, t.Err) 53 | } 54 | 55 | // A token is a token in a DER ASCII file. 56 | type token struct { 57 | // Kind is the kind of the token. 58 | Kind tokenKind 59 | // Value, for a tokenBytes token, is the decoded value of the token in 60 | // bytes. 61 | Value []byte 62 | // Pos is the position of the first byte of the token. 63 | Pos position 64 | } 65 | 66 | var ( 67 | regexpInteger = regexp.MustCompile(`^-?[0-9]+$`) 68 | regexpOID = regexp.MustCompile(`^[0-9]+(\.[0-9]+)+$`) 69 | ) 70 | 71 | type scanner struct { 72 | text string 73 | pos position 74 | } 75 | 76 | func newScanner(text string) *scanner { 77 | return &scanner{text: text, pos: position{Line: 1}} 78 | } 79 | 80 | func (s *scanner) Next() (token, error) { 81 | again: 82 | if s.isEOF() { 83 | return token{Kind: tokenEOF, Pos: s.pos}, nil 84 | } 85 | 86 | switch s.text[s.pos.Offset] { 87 | case ' ', '\t', '\n', '\r': 88 | // Skip whitespace. 89 | s.advance() 90 | goto again 91 | case '#': 92 | // Skip to the end of the comment. 93 | s.advance() 94 | for !s.isEOF() { 95 | wasNewline := s.text[s.pos.Offset] == '\n' 96 | s.advance() 97 | if wasNewline { 98 | break 99 | } 100 | } 101 | goto again 102 | case '{': 103 | s.advance() 104 | return token{Kind: tokenLeftCurly, Pos: s.pos}, nil 105 | case '}': 106 | s.advance() 107 | return token{Kind: tokenRightCurly, Pos: s.pos}, nil 108 | case '"': 109 | s.advance() 110 | start := s.pos 111 | var bytes []byte 112 | for { 113 | if s.isEOF() { 114 | return token{}, &parseError{start, errors.New("unmatched \"")} 115 | } 116 | switch c := s.text[s.pos.Offset]; c { 117 | case '"': 118 | s.advance() 119 | return token{Kind: tokenBytes, Value: bytes, Pos: start}, nil 120 | case '\\': 121 | s.advance() 122 | if s.isEOF() { 123 | return token{}, &parseError{s.pos, errors.New("expected escape character")} 124 | } 125 | switch c2 := s.text[s.pos.Offset]; c2 { 126 | case 'n': 127 | bytes = append(bytes, '\n') 128 | case '"', '\\': 129 | bytes = append(bytes, c2) 130 | case 'x': 131 | s.advance() 132 | if s.pos.Offset+2 > len(s.text) { 133 | return token{}, &parseError{s.pos, errors.New("unfinished escape sequence")} 134 | } 135 | b, err := hex.DecodeString(s.text[s.pos.Offset : s.pos.Offset+2]) 136 | if err != nil { 137 | return token{}, &parseError{s.pos, err} 138 | } 139 | bytes = append(bytes, b[0]) 140 | s.advance() 141 | default: 142 | return token{}, &parseError{s.pos, fmt.Errorf("unknown escape sequence \\%c", c2)} 143 | } 144 | default: 145 | bytes = append(bytes, c) 146 | } 147 | s.advance() 148 | } 149 | case '`': 150 | s.advance() 151 | hexStr, ok := s.consumeUpTo('`') 152 | if !ok { 153 | return token{}, &parseError{s.pos, errors.New("unmatched `")} 154 | } 155 | bytes, err := hex.DecodeString(hexStr) 156 | if err != nil { 157 | return token{}, &parseError{s.pos, err} 158 | } 159 | return token{Kind: tokenBytes, Value: bytes, Pos: s.pos}, nil 160 | case '[': 161 | s.advance() 162 | tagStr, ok := s.consumeUpTo(']') 163 | if !ok { 164 | return token{}, &parseError{s.pos, errors.New("unmatched [")} 165 | } 166 | tag, err := decodeTagString(tagStr) 167 | if err != nil { 168 | return token{}, &parseError{s.pos, err} 169 | } 170 | return token{Kind: tokenBytes, Value: appendTag(nil, tag), Pos: s.pos}, nil 171 | } 172 | 173 | // Normal token. Consume up to the next whitespace character, symbol, or 174 | // EOF. 175 | start := s.pos 176 | s.advance() 177 | loop: 178 | for !s.isEOF() { 179 | switch s.text[s.pos.Offset] { 180 | case ' ', '\t', '\n', '\r', '{', '}', '[', ']', '`', '"', '#': 181 | break loop 182 | default: 183 | s.advance() 184 | } 185 | } 186 | 187 | symbol := s.text[start.Offset:s.pos.Offset] 188 | 189 | // See if it is a tag. 190 | tag, ok := lib.TagByName(symbol) 191 | if ok { 192 | return token{Kind: tokenBytes, Value: appendTag(nil, tag), Pos: start}, nil 193 | } 194 | 195 | if regexpInteger.MatchString(symbol) { 196 | value, err := strconv.ParseInt(symbol, 10, 64) 197 | if err != nil { 198 | return token{}, &parseError{start, err} 199 | } 200 | return token{Kind: tokenBytes, Value: appendInteger(nil, value), Pos: s.pos}, nil 201 | } 202 | 203 | if regexpOID.MatchString(symbol) { 204 | oidStr := strings.Split(symbol, ".") 205 | var oid []uint32 206 | for _, s := range oidStr { 207 | u, err := strconv.ParseUint(s, 10, 32) 208 | if err != nil { 209 | return token{}, &parseError{start, err} 210 | } 211 | oid = append(oid, uint32(u)) 212 | } 213 | der, ok := appendObjectIdentifier(nil, oid) 214 | if !ok { 215 | return token{}, errors.New("invalid OID") 216 | } 217 | return token{Kind: tokenBytes, Value: der, Pos: s.pos}, nil 218 | } 219 | 220 | return token{}, fmt.Errorf("unrecognized symbol '%s'", symbol) 221 | } 222 | 223 | func (s *scanner) isEOF() bool { 224 | return s.pos.Offset >= len(s.text) 225 | } 226 | 227 | func (s *scanner) advance() { 228 | if !s.isEOF() { 229 | if s.text[s.pos.Offset] == '\n' { 230 | s.pos.Line++ 231 | s.pos.Column = 0 232 | } else { 233 | s.pos.Column++ 234 | } 235 | s.pos.Offset++ 236 | } 237 | } 238 | 239 | func (s *scanner) consumeUpTo(b byte) (string, bool) { 240 | start := s.pos.Offset 241 | for !s.isEOF() { 242 | if s.text[s.pos.Offset] == b { 243 | ret := s.text[start:s.pos.Offset] 244 | s.advance() 245 | return ret, true 246 | } 247 | s.advance() 248 | } 249 | return "", false 250 | } 251 | 252 | func asciiToDERImpl(scanner *scanner, leftCurly *token) ([]byte, error) { 253 | var out []byte 254 | for { 255 | token, err := scanner.Next() 256 | if err != nil { 257 | return nil, err 258 | } 259 | switch token.Kind { 260 | case tokenBytes: 261 | out = append(out, token.Value...) 262 | case tokenLeftCurly: 263 | child, err := asciiToDERImpl(scanner, &token) 264 | if err != nil { 265 | return nil, err 266 | } 267 | out = appendLength(out, len(child)) 268 | out = append(out, child...) 269 | case tokenRightCurly: 270 | if leftCurly != nil { 271 | return out, nil 272 | } 273 | return nil, &parseError{token.Pos, errors.New("unmatched '}'")} 274 | case tokenEOF: 275 | if leftCurly == nil { 276 | return out, nil 277 | } 278 | return nil, &parseError{leftCurly.Pos, errors.New("unmatched '{'")} 279 | default: 280 | panic(token) 281 | } 282 | } 283 | } 284 | 285 | func asciiToDER(input string) ([]byte, error) { 286 | scanner := newScanner(input) 287 | return asciiToDERImpl(scanner, nil) 288 | } 289 | -------------------------------------------------------------------------------- /der2ascii/writer.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The DER ASCII Authors. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "encoding/hex" 19 | "fmt" 20 | "strconv" 21 | "unicode" 22 | 23 | "github.com/google/der-ascii/lib" 24 | ) 25 | 26 | type writer struct { 27 | out string 28 | indent int 29 | } 30 | 31 | func (w *writer) String() string { 32 | return w.out 33 | } 34 | 35 | func (w *writer) SetIndent(indent int) { 36 | w.indent = indent 37 | } 38 | 39 | func (w *writer) Indent() int { 40 | return w.indent 41 | } 42 | 43 | func (w *writer) AddIndent(v int) { 44 | w.indent += v 45 | } 46 | 47 | func (w *writer) WriteLine(line string) { 48 | for i := 0; i < w.indent; i++ { 49 | w.out += " " 50 | } 51 | w.out += line 52 | w.out += "\n" 53 | } 54 | 55 | // isMadeOfElements returns true if bytes can be parsed as a series of DER 56 | // elements with no trailing data and false otherwise. 57 | func isMadeOfElements(bytes []byte) bool { 58 | var indefiniteCount int 59 | for len(bytes) != 0 { 60 | if indefiniteCount > 0 && len(bytes) >= 2 && bytes[0] == 0 && bytes[1] == 0 { 61 | bytes = bytes[2:] 62 | indefiniteCount-- 63 | continue 64 | } 65 | 66 | _, _, indefinite, rest, ok := parseElement(bytes) 67 | if !ok { 68 | return false 69 | } 70 | bytes = rest 71 | if indefinite { 72 | indefiniteCount++ 73 | } 74 | } 75 | return indefiniteCount == 0 76 | } 77 | 78 | func classToString(class lib.Class) string { 79 | switch class { 80 | case lib.ClassUniversal: 81 | return "UNIVERSAL" 82 | case lib.ClassApplication: 83 | return "APPLICATION" 84 | case lib.ClassContextSpecific: 85 | panic("should not be called") 86 | case lib.ClassPrivate: 87 | return "PRIVATE" 88 | default: 89 | panic(class) 90 | } 91 | } 92 | 93 | func tagToString(tag lib.Tag) string { 94 | // Write a short name if possible. 95 | name, toggleConstructed, ok := tag.GetAlias() 96 | if ok { 97 | if !toggleConstructed { 98 | return name 99 | } 100 | constructed := "PRIMITIVE" 101 | if tag.Constructed { 102 | constructed = "CONSTRUCTED" 103 | } 104 | return fmt.Sprintf("[%s %s]", name, constructed) 105 | } 106 | 107 | out := "[" 108 | if tag.Class != lib.ClassContextSpecific { 109 | out += fmt.Sprintf("%s ", classToString(tag.Class)) 110 | } 111 | out += fmt.Sprintf("%d", tag.Number) 112 | if !tag.Constructed { 113 | out += " PRIMITIVE" 114 | } 115 | out += "]" 116 | return out 117 | } 118 | 119 | func bytesToString(bytes []byte) string { 120 | if len(bytes) == 0 { 121 | return "" 122 | } 123 | 124 | var asciiCount int 125 | for _, b := range bytes { 126 | if b < 0x80 && (b == '\n' || unicode.IsPrint(rune(b))) { 127 | asciiCount++ 128 | } 129 | } 130 | 131 | if float64(asciiCount)/float64(len(bytes)) > 0.85 { 132 | return bytesToQuotedString(bytes) 133 | } else { 134 | return bytesToHexString(bytes) 135 | } 136 | } 137 | 138 | func bytesToHexString(bytes []byte) string { 139 | return fmt.Sprintf("`%s`", hex.EncodeToString(bytes)) 140 | } 141 | 142 | func bytesToQuotedString(bytes []byte) string { 143 | out := `"` 144 | for _, b := range bytes { 145 | if b == '\n' { 146 | out += `\n` 147 | } else if b == '"' { 148 | out += `\"` 149 | } else if b == '\\' { 150 | out += `\\` 151 | } else if b >= 0x80 || !unicode.IsPrint(rune(b)) { 152 | out += fmt.Sprintf(`\x%02x`, b) 153 | } else { 154 | out += string([]byte{b}) 155 | } 156 | } 157 | out += `"` 158 | return out 159 | } 160 | 161 | func integerToString(bytes []byte) string { 162 | v, ok := decodeInteger(bytes) 163 | if ok && -100000 <= v && v <= 100000 { 164 | return strconv.FormatInt(v, 10) 165 | } 166 | return bytesToHexString(bytes) 167 | } 168 | 169 | func objectIdentifierToString(bytes []byte) string { 170 | oid, ok := decodeObjectIdentifier(bytes) 171 | if !ok { 172 | return bytesToHexString(bytes) 173 | } 174 | var out string 175 | for i, v := range oid { 176 | if i != 0 { 177 | out += "." 178 | } 179 | out += strconv.FormatUint(uint64(v), 10) 180 | } 181 | return out 182 | } 183 | 184 | func derToASCIIImpl(w *writer, bytes []byte, stopAtEOC bool) []byte { 185 | for len(bytes) != 0 { 186 | if stopAtEOC && len(bytes) >= 2 && bytes[0] == 0 && bytes[1] == 0 { 187 | // Emit a `0000` in lieu of a closing base. 188 | w.AddIndent(-1) 189 | w.WriteLine(bytesToString(bytes[:2])) 190 | return bytes[2:] 191 | } 192 | 193 | tag, body, indefinite, rest, ok := parseElement(bytes) 194 | if !ok { 195 | // Nothing more to encode. Write the rest as bytes. 196 | w.WriteLine(bytesToString(bytes)) 197 | return nil 198 | } 199 | bytes = rest 200 | 201 | if indefinite { 202 | // Emit a `80` in lieu of an open brace. 203 | w.WriteLine(fmt.Sprintf("%s `80`", tagToString(tag))) 204 | indent := w.Indent() 205 | w.AddIndent(1) 206 | bytes = derToASCIIImpl(w, bytes, true) 207 | // If EOC was missing, the indent may not have been 208 | // restored correctly. 209 | w.SetIndent(indent) 210 | continue 211 | } 212 | 213 | if len(body) == 0 { 214 | // If the body is empty, skip the newlines. 215 | w.WriteLine(fmt.Sprintf("%s {}", tagToString(tag))) 216 | continue 217 | } 218 | 219 | if tag.Constructed { 220 | // If the element is constructed, recurse. 221 | w.WriteLine(fmt.Sprintf("%s {", tagToString(tag))) 222 | w.AddIndent(1) 223 | derToASCIIImpl(w, body, false) 224 | w.AddIndent(-1) 225 | w.WriteLine("}") 226 | } else { 227 | // The element is primitive. By default, emit the body 228 | // on the same line as curly braces. However, in some 229 | // cases, we heuristically decode the body as DER too. 230 | // In this case, the newlines are inserted as in the 231 | // constructed case. 232 | 233 | // If ok is false, name will be empty. There is also no 234 | // need to check toggleConstructed as we already know 235 | // the tag is primitive. 236 | name, _, _ := tag.GetAlias() 237 | switch name { 238 | case "INTEGER": 239 | w.WriteLine(fmt.Sprintf("%s { %s }", tagToString(tag), integerToString(body))) 240 | case "OBJECT_IDENTIFIER": 241 | w.WriteLine(fmt.Sprintf("%s { %s }", tagToString(tag), objectIdentifierToString(body))) 242 | case "BIT_STRING": 243 | // X.509 encodes signatures and SPKIs in BIT 244 | // STRINGs, so there is a 0 phase byte followed 245 | // by the potentially DER-encoded structure. 246 | if len(body) > 1 && body[0] == 0 && isMadeOfElements(body[1:]) { 247 | w.WriteLine(fmt.Sprintf("%s {", tagToString(tag))) 248 | w.AddIndent(1) 249 | // Emit the phase byte. 250 | w.WriteLine(bytesToString(body[:1])) 251 | // Emit the remaining as a DER element. 252 | derToASCIIImpl(w, body[1:], false) // Adds a trailing newline. 253 | w.AddIndent(-1) 254 | w.WriteLine("}") 255 | } else { 256 | w.WriteLine(fmt.Sprintf("%s { %s }", tagToString(tag), bytesToString(body))) 257 | } 258 | default: 259 | // Keep parsing if the body looks like ASN.1. 260 | // 261 | // TODO(davidben): This is O(N^2) for deeply- 262 | // nested indefinite-length encodings inside 263 | // primitive elements. 264 | if isMadeOfElements(body) { 265 | w.WriteLine(fmt.Sprintf("%s {", tagToString(tag))) 266 | w.AddIndent(1) 267 | derToASCIIImpl(w, body, false) 268 | w.AddIndent(-1) 269 | w.WriteLine("}") 270 | } else { 271 | w.WriteLine(fmt.Sprintf("%s { %s }", tagToString(tag), bytesToString(body))) 272 | } 273 | } 274 | } 275 | } 276 | return nil 277 | } 278 | 279 | func derToASCII(bytes []byte) string { 280 | var w writer 281 | derToASCIIImpl(&w, bytes, false) 282 | return w.String() 283 | } 284 | -------------------------------------------------------------------------------- /der2ascii/decoder_test.go: -------------------------------------------------------------------------------- 1 | // Copyright 2015 The DER ASCII Authors. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package main 16 | 17 | import ( 18 | "bytes" 19 | "math" 20 | "testing" 21 | 22 | "github.com/google/der-ascii/lib" 23 | ) 24 | 25 | var parseTagTests = []struct { 26 | in []byte 27 | tag lib.Tag 28 | ok bool 29 | }{ 30 | {[]byte{0x30}, lib.Tag{lib.ClassUniversal, 16, true}, true}, 31 | {[]byte{0x02}, lib.Tag{lib.ClassUniversal, 2, false}, true}, 32 | {[]byte{0x7f, 0x89, 0x52}, lib.Tag{lib.ClassApplication, 1234, true}, true}, 33 | // Empty. 34 | {[]byte{}, lib.Tag{}, false}, 35 | // Truncated high-tag-number-form. 36 | {[]byte{0x7f}, lib.Tag{}, false}, 37 | {[]byte{0x7f, 0xff}, lib.Tag{}, false}, 38 | // Should have been low-tag-number form. 39 | {[]byte{0x7f, 0x01}, lib.Tag{}, false}, 40 | // Non-minimal encoding. 41 | {[]byte{0x7f, 0x00, 0x89, 0x52, 0x00}, lib.Tag{}, false}, 42 | // Overflow. 43 | {[]byte{0xff, 0x8f, 0xff, 0xff, 0xff, 0x7f}, lib.Tag{lib.ClassPrivate, (1 << 32) - 1, true}, true}, 44 | {[]byte{0xff, 0x9f, 0xff, 0xff, 0xff, 0x7f}, lib.Tag{}, false}, 45 | // EOC. 46 | {[]byte{0x00}, lib.Tag{}, false}, 47 | } 48 | 49 | func TestParseTag(t *testing.T) { 50 | for i, tt := range parseTagTests { 51 | tag, rest, ok := parseTag(tt.in) 52 | if !tt.ok { 53 | if ok { 54 | t.Errorf("%d. parseTag(%v) unexpectedly succeeded.", i, tt.in) 55 | } else if !bytes.Equal(rest, tt.in) { 56 | t.Errorf("%d. parseTag(%v) did not preserve input.", i, tt.in) 57 | } 58 | } else { 59 | if !ok { 60 | t.Errorf("%d. parseTag(%v) unexpectedly failed.", i, tt.in) 61 | } else if tag != tt.tag || len(rest) != 0 { 62 | t.Errorf("%d. parseTag(%v) = %v, %v wanted %v, [].", i, tt.in, tag, rest, tt.tag) 63 | } 64 | 65 | // Test again with trailing data. 66 | in := make([]byte, len(tt.in)+5) 67 | copy(in, tt.in) 68 | tag, rest, ok = parseTag(in) 69 | if !ok { 70 | t.Errorf("%d. parseTag(%v) unexpectedly failed.", i, in) 71 | } else if tag != tt.tag || !bytes.Equal(rest, in[len(tt.in):]) { 72 | t.Errorf("%d. parseTag(%v) = %v, %v wanted %v, %v.", i, in, tag, rest, tt.tag, in[len(tt.in):]) 73 | } 74 | } 75 | } 76 | } 77 | 78 | var sequenceTag = lib.Tag{lib.ClassUniversal, 16, true} 79 | 80 | var parseTagAndLengthTests = []struct { 81 | in []byte 82 | tag lib.Tag 83 | length int 84 | indefinite bool 85 | ok bool 86 | }{ 87 | // Short-form length. 88 | {[]byte{0x30, 0x00}, sequenceTag, 0, false, true}, 89 | {[]byte{0x30, 0x01}, sequenceTag, 1, false, true}, 90 | // Indefinite length. 91 | {[]byte{0x30, 0x80}, sequenceTag, 0, true, true}, 92 | // Long-form length. 93 | {[]byte{0x30, 0x81, 0x80}, sequenceTag, 128, false, true}, 94 | {[]byte{0x30, 0x81, 0xff}, sequenceTag, 255, false, true}, 95 | {[]byte{0x30, 0x82, 0x01, 0x00}, sequenceTag, 256, false, true}, 96 | // Too short. 97 | {[]byte{0x30}, lib.Tag{}, 0, false, false}, 98 | {[]byte{0x30, 0x81}, lib.Tag{}, 0, false, false}, 99 | // Non-minimal form length. 100 | {[]byte{0x30, 0x82, 0x00, 0xff}, lib.Tag{}, 0, false, false}, 101 | {[]byte{0x30, 0x81, 0x1f}, lib.Tag{}, 0, false, false}, 102 | // Overflow. 103 | {[]byte{0x30, 0x85, 0xff, 0xff, 0xff, 0xff, 0xff}, lib.Tag{}, 0, false, false}, 104 | // Empty. 105 | {[]byte{}, lib.Tag{}, 0, false, false}, 106 | // Primitive + indefinite length is illegal. 107 | {[]byte{0x02, 0x80}, lib.Tag{}, 0, false, false}, 108 | } 109 | 110 | func TestParseTagAndLength(t *testing.T) { 111 | for i, tt := range parseTagAndLengthTests { 112 | tag, length, indefinite, rest, ok := parseTagAndLength(tt.in) 113 | if !tt.ok { 114 | if ok { 115 | t.Errorf("%d. parseTagAndLength(%v) unexpectedly succeeded.", i, tt.in) 116 | } else if !bytes.Equal(rest, tt.in) { 117 | t.Errorf("%d. parseTagAndLength(%v) did not preserve input.", i, tt.in) 118 | } 119 | } else { 120 | if !ok { 121 | t.Errorf("%d. parseTagAndLength(%v) unexpectedly failed.", i, tt.in) 122 | } else if tag != tt.tag || length != tt.length || indefinite != tt.indefinite || len(rest) != 0 { 123 | t.Errorf("%d. parseTagAndLength(%v) = %v, %v, %v, %v wanted %v, %v, %v, [].", i, tt.in, tag, length, indefinite, rest, tt.tag, tt.length, tt.indefinite) 124 | } 125 | 126 | // Test again with trailing data. 127 | in := make([]byte, len(tt.in)+5) 128 | copy(in, tt.in) 129 | tag, length, indefinite, rest, ok := parseTagAndLength(in) 130 | if !ok { 131 | t.Errorf("%d. parseTagAndLength(%v) unexpectedly failed.", i, in) 132 | } else if tag != tt.tag || length != tt.length || indefinite != tt.indefinite || !bytes.Equal(rest, in[len(tt.in):]) { 133 | t.Errorf("%d. parseTagAndLength(%v) = %v, %v, %v, %v wanted %v, %v.", i, in, tag, length, indefinite, rest, tt.tag, tt.length, tt.indefinite, in[len(tt.in):]) 134 | } 135 | } 136 | } 137 | } 138 | 139 | var parseElementTests = []struct { 140 | in []byte 141 | tag lib.Tag 142 | body []byte 143 | indefinite bool 144 | ok bool 145 | }{ 146 | // Normal element. 147 | {[]byte{0x30, 0x00}, sequenceTag, []byte{}, false, true}, 148 | {[]byte{0x30, 0x01, 0xaa}, sequenceTag, []byte{0xaa}, false, true}, 149 | // Indefinite length. 150 | {[]byte{0x30, 0x80}, sequenceTag, nil, true, true}, 151 | // Too short. 152 | {[]byte{0x30}, lib.Tag{}, []byte{}, false, false}, 153 | {[]byte{0x30, 0x01}, lib.Tag{}, []byte{}, false, false}, 154 | {[]byte{0x30, 0x81}, lib.Tag{}, []byte{}, false, false}, 155 | } 156 | 157 | func TestParseElement(t *testing.T) { 158 | for i, tt := range parseElementTests { 159 | tag, body, indefinite, rest, ok := parseElement(tt.in) 160 | if !tt.ok { 161 | if ok { 162 | t.Errorf("%d. parseElement(%v) unexpectedly succeeded.", i, tt.in) 163 | } else if !bytes.Equal(rest, tt.in) { 164 | t.Errorf("%d. parseElement(%v) did not preserve input.", i, tt.in) 165 | } 166 | } else { 167 | if !ok { 168 | t.Errorf("%d. parseElement(%v) unexpectedly failed.", i, tt.in) 169 | } else if tag != tt.tag || !bytes.Equal(body, tt.body) || indefinite != tt.indefinite || len(rest) != 0 { 170 | t.Errorf("%d. parseElement(%v) = %v, %v, %v, %v wanted %v, %v, %v, [].", i, tt.in, tag, body, indefinite, rest, tt.tag, tt.body, tt.indefinite) 171 | } 172 | 173 | // Test again with trailing data. 174 | in := make([]byte, len(tt.in)+5) 175 | copy(in, tt.in) 176 | tag, body, indefinite, rest, ok := parseElement(in) 177 | if !ok { 178 | t.Errorf("%d. parseElement(%v) unexpectedly failed.", i, in) 179 | } else if tag != tt.tag || !bytes.Equal(body, tt.body) || indefinite != tt.indefinite || !bytes.Equal(rest, in[len(tt.in):]) { 180 | t.Errorf("%d. parseElement(%v) = %v, %v, %v, %v wanted %v, %v.", i, in, tag, body, indefinite, rest, tt.tag, tt.body, tt.indefinite, in[len(tt.in):]) 181 | } 182 | } 183 | } 184 | } 185 | 186 | var decodeIntegerTests = []struct { 187 | in []byte 188 | out int64 189 | ok bool 190 | }{ 191 | // Valid encodings. 192 | {[]byte{0x00}, 0, true}, 193 | {[]byte{0x01}, 1, true}, 194 | {[]byte{0xff}, -1, true}, 195 | {[]byte{0x7f}, 127, true}, 196 | {[]byte{0x00, 0x80}, 128, true}, 197 | {[]byte{0x01, 0x00}, 256, true}, 198 | {[]byte{0x80}, -128, true}, 199 | {[]byte{0xff, 0x7f}, -129, true}, 200 | // Empty encoding. 201 | {[]byte{}, 0, false}, 202 | // Non-minimal encodings. 203 | {[]byte{0x00, 0x01}, 0, false}, 204 | {[]byte{0xff, 0xff}, 0, false}, 205 | // Overflow tests. 206 | {[]byte{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, (1 << 63) - 1, true}, 207 | {[]byte{0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 0, false}, 208 | {[]byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, -(1 << 63), true}, 209 | {[]byte{0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, 0, false}, 210 | } 211 | 212 | func TestDecodeInteger(t *testing.T) { 213 | for i, tt := range decodeIntegerTests { 214 | out, ok := decodeInteger(tt.in) 215 | if !tt.ok { 216 | if ok { 217 | t.Errorf("%d. decodeInteger(%v) unexpectedly succeeded.", i, tt.in) 218 | } 219 | } else if !ok { 220 | t.Errorf("%d. decodeInteger(%v) unexpectedly failed.", i, tt.in) 221 | } else if out != tt.out { 222 | t.Errorf("%d. decodeInteger(%v) = %v wanted %v.", i, tt.in, out, tt.out) 223 | } 224 | } 225 | } 226 | 227 | func eqUint32s(a, b []uint32) bool { 228 | if len(a) != len(b) { 229 | return false 230 | } 231 | for i := range a { 232 | if a[i] != b[i] { 233 | return false 234 | } 235 | } 236 | return true 237 | } 238 | 239 | var decodeObjectIdentifierTests = []struct { 240 | in []byte 241 | out []uint32 242 | ok bool 243 | }{ 244 | {[]byte{1}, []uint32{0, 1}, true}, 245 | {[]byte{42, 3, 4, 0x7f, 0x81, 0x00, 0x81, 0x01}, []uint32{1, 2, 3, 4, 127, 128, 129}, true}, 246 | {[]byte{81}, []uint32{2, 1}, true}, 247 | {[]byte{0x8f, 0xff, 0xff, 0xff, 0x7f}, []uint32{2, math.MaxUint32 - 80}, true}, 248 | // Empty. 249 | {[]byte{}, nil, false}, 250 | // Incomplete component. 251 | {[]byte{0xff}, nil, false}, 252 | // Overflow. 253 | {[]byte{0x9f, 0xff, 0xff, 0xff, 0x7f}, nil, false}, 254 | } 255 | 256 | func TestDecodeObjectIdentifier(t *testing.T) { 257 | for i, tt := range decodeObjectIdentifierTests { 258 | out, ok := decodeObjectIdentifier(tt.in) 259 | if !tt.ok { 260 | if ok { 261 | t.Errorf("%d. decodeObjectIdentifier(%v) unexpectedly succeeded.", i, tt.in) 262 | } 263 | } else if !ok { 264 | t.Errorf("%d. decodeObjectIdentifier(%v) unexpectedly failed.", i, tt.in) 265 | } else if !eqUint32s(out, tt.out) { 266 | t.Errorf("%d. decodeObjectIdentifier(%v) = %v wanted %v.", i, tt.in, out, tt.out) 267 | } 268 | } 269 | } 270 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | --------------------------------------------------------------------------------