Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract ascii2der into a library package #22

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 48 additions & 6 deletions cmd/ascii2der/encoder.go → ascii2der/encoder.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,45 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package main
package ascii2der

import (
"errors"
"fmt"
"unicode/utf16"

"github.com/google/der-ascii/internal"
)

// appendUTF16 marshals r using UTF-16 and appends the result to dst, returning
// the updated slice.
//
// This logic intentionally tolerates unpaired surrogates.
func appendUTF16(dst []byte, r rune) []byte {
if r <= 0xffff {
return append(dst, byte(r>>8), byte(r))
}

r1, r2 := utf16.EncodeRune(r)
dst = append(dst, byte(r1>>8), byte(r1))
dst = append(dst, byte(r2>>8), byte(r2))
return dst
}

// appendUTF16 marshals r using UTF-32 and appends the result to dst, returning
// the updated slice.
//
// In other words, this function writes r as an integer in big-endian order.
func appendUTF32(dst []byte, r rune) []byte {
return append(dst, byte(r>>24), byte(r>>16), byte(r>>8), byte(r))
}

// appendBase128 marshals an integer in base 128, a varint format used by OIDs
// and long-form tag numbers, and appends the result to dst, returning the
// updated slice.
//
// This function is the same as appendBase128WithLength with length set to zero,
// which cannot fail.
func appendBase128(dst []byte, value uint32) []byte {
dst, err := appendBase128WithLength(dst, value, 0)
if err != nil {
Expand All @@ -30,6 +60,11 @@ func appendBase128(dst []byte, value uint32) []byte {
return dst
}

// appendBase128 marshals an integer in base 128, a varint format used by OIDs
// and long-form tag numbers, and appends the result to dst, returning the
// updated slice.
//
// If length is zero, the minimal length is chosen.
func appendBase128WithLength(dst []byte, value uint32, length int) ([]byte, error) {
// Count how many bytes are needed.
var l int
Expand Down Expand Up @@ -120,18 +155,25 @@ func appendInteger(dst []byte, value int64) []byte {
return dst
}

func appendObjectIdentifier(dst []byte, value []uint32) ([]byte, bool) {
// appendObjectIdentifier marshals the given array of integers as an OID.
func appendObjectIdentifier(dst []byte, value []uint32) ([]byte, error) {
// Validate the input before anything is written.
if len(value) < 2 || value[0] > 2 || (value[0] < 2 && value[1] > 39) {
return dst, false
if len(value) < 2 {
return dst, errors.New("OIDs must have at least two arcs")
}
if value[0] > 2 {
return dst, fmt.Errorf("first arc of an OID must be one of 0, 1, or 2; got %d", value[0])
}
if value[0] < 2 && value[1] > 39 {
return dst, fmt.Errorf("second arc of an OID must be at most 39; got %d", value[1])
}
if value[0]*40+value[1] < value[1] {
return dst, false
return dst, errors.New("first two arcs overflowed")
}

dst = appendBase128(dst, value[0]*40+value[1])
for _, v := range value[2:] {
dst = appendBase128(dst, v)
}
return dst, true
return dst, nil
}
12 changes: 6 additions & 6 deletions cmd/ascii2der/encoder_test.go → ascii2der/encoder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

package main
package ascii2der

import (
"bytes"
Expand Down Expand Up @@ -162,21 +162,21 @@ var appendObjectIdentifierTests = []struct {

func TestAppendObjectIdentifier(t *testing.T) {
for i, tt := range appendObjectIdentifierTests {
dst, ok := appendObjectIdentifier(nil, tt.value)
dst, err := appendObjectIdentifier(nil, tt.value)
if !tt.ok {
if ok {
if err == nil {
t.Errorf("%d. appendObjectIdentifier(nil, %v) unexpectedly suceeded.", i, tt.value)
} else if len(dst) != 0 {
t.Errorf("%d. appendObjectIdentifier did not preserve input.", i)
}
} else if !bytes.Equal(dst, tt.encoded) {
t.Errorf("%d. appendObjectIdentifier(nil, %v) = %v, wanted %v.", i, tt.value, dst, tt.encoded)
t.Errorf("%d. appendObjectIdentifier(nil, %v) = %v, %v, wanted %v.", i, tt.value, dst, err, tt.encoded)
}

dst = []byte{0}
dst, ok = appendObjectIdentifier(dst, tt.value)
dst, err = appendObjectIdentifier(dst, tt.value)
if !tt.ok {
if ok {
if err == nil {
t.Errorf("%d. appendObjectIdentifier(nil, %v) unexpectedly suceeded.", i, tt.value)
} else if !bytes.Equal(dst, []byte{0}) {
t.Errorf("%d. appendObjectIdentifier did not preserve input.", i)
Expand Down
31 changes: 31 additions & 0 deletions ascii2der/examples_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2015 The DER ASCII Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package ascii2der

import (
"fmt"
)

func Example() {
scanner := NewScanner(`
SEQUENCE {
INTEGER { "totally an integer" }
}
`)

der, _ := scanner.Exec()
fmt.Printf("%x\n", der)
// Output: 30140212746f74616c6c7920616e20696e7465676572
}
Loading