Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 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
71 changes: 52 additions & 19 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,28 +1,61 @@
name: CI
on: [push, pull_request]

env:
GODEBUG: x509sha1=1
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]

jobs:
lint:
name: Lint
strategy:
matrix:
go: ["1.19", "1.20", "1.21", "1.22", "1.23", "1.24"]
Comment thread
vanbroup marked this conversation as resolved.
Outdated
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: ${{ matrix.go }}
- name: golangci-lint
uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0
with:
version: v2.3.0

test:
name: Test
strategy:
matrix:
go: ['1.13', '1.14', '1.15', '1.16', '1.17', '1.18', '1.19']
go: ["1.19", "1.20", "1.21", "1.22", "1.23", "1.24"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go }}
- name: Test
run: |
go vet .
go build .
go test -count=1 -covermode=count -coverprofile=coverage.out .

legacy-test:
name: Legacy Tests
strategy:
matrix:
go: ["1.19", "1.20", "1.21", "1.22", "1.23"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-go@v2
with:
go-version: ${{ matrix.go }}
stable: false
- name: Test
env:
# set this environment variable to true so tests can be run with the
# sha1 algorithm. Without this set, tests fail because Go notes the
# SHA1 algorithm as insecure
GODEBUG: x509sha1=1
run: go vet . && go build . && go test -count=1 -covermode=count -coverprofile=coverage.out .
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go }}
- name: Test
run: |
go vet -tags=legacy .
go build -tags=legacy .
GODEBUG=x509sha1=1 go test -tags=legacy -count=1 -covermode=count -coverprofile=coverage.out . -run "^TestLegacy.*$"
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,6 @@ _testmain.go
*.exe
*.test
*.prof

# Coverage reports
coverage.out
66 changes: 66 additions & 0 deletions .golangci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
version: "2"
linters:
enable:
- copyloopvar
- goconst
- gocyclo
- gosec
- misspell
- nolintlint
- prealloc
- revive
- unconvert
- unparam
settings:
gocyclo:
min-complexity: 90 # Allow very high complexity for crypto functions and test utilities
gosec:
excludes:
- G401 # Allow weak crypto algorithms as this is a crypto library
- G501 # Allow import of blacklisted crypto/md5
- G505 # Allow import of blacklisted crypto/sha1
- G502 # Allow import of blacklisted crypto/des
- G405 # Allow use of weak cryptographic primitive
- G306 # Allow WriteFile permissions for test files
- G204 # Allow subprocess launches in tests (OpenSSL integration)
- G115 # Allow integer overflow conversion
revive:
rules:
- name: exported
disabled: true # Disable exported rule for crypto library
staticcheck:
checks:
- all
exclusions:
generated: lax
presets:
- comments
- common-false-positives
- legacy
- std-error-handling
rules:
# Allow specific deprecated crypto algorithms that are needed for PKCS#7 compatibility
- linters:
- staticcheck
text: SA1019.*crypto/dsa.*has been deprecated
- linters:
- staticcheck
text: SA1019.*crypto/sha1.*is deprecated
- linters:
- staticcheck
text: SA1019.*crypto/md5.*is deprecated
paths:
- third_party$
- builtin$
- examples$
formatters:
enable:
- gofmt
- gofumpt
- goimports
exclusions:
generated: lax
paths:
- third_party$
- builtin$
- examples$
17 changes: 8 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
all: vet staticcheck test
all: vet test

test:
GODEBUG=x509sha1=1 go test -covermode=count -coverprofile=coverage.out .
go test -covermode=count -coverprofile=coverage.out .

test-legacy:
GODEBUG=x509sha1=1 go test -tags=legacy -covermode=count -coverprofile=coverage.out .

showcoverage: test
go tool cover -html=coverage.out

vet:
go vet .

lint:
golint .

staticcheck:
staticcheck .
golangci-lint:
golangci-lint run

gettools:
go get -u honnef.co/go/tools/...
go get -u golang.org/x/lint/golint
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
38 changes: 19 additions & 19 deletions ber.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ type asn1Structured struct {
}

func (s asn1Structured) EncodeTo(out *bytes.Buffer) error {
//fmt.Printf("%s--> tag: % X\n", strings.Repeat("| ", encodeIndent), s.tagBytes)
// fmt.Printf("%s--> tag: % X\n", strings.Repeat("| ", encodeIndent), s.tagBytes)
inner := new(bytes.Buffer)
for _, obj := range s.content {
err := obj.EncodeTo(inner)
Expand All @@ -24,7 +24,7 @@ func (s asn1Structured) EncodeTo(out *bytes.Buffer) error {
}
}
out.Write(s.tagBytes)
encodeLength(out, inner.Len())
_ = encodeLength(out, inner.Len())
out.Write(inner.Bytes())
return nil
}
Expand All @@ -43,8 +43,8 @@ func (p asn1Primitive) EncodeTo(out *bytes.Buffer) error {
if err = encodeLength(out, p.length); err != nil {
return err
}
//fmt.Printf("%s--> tag: % X length: %d\n", strings.Repeat("| ", encodeIndent), p.tagBytes, p.length)
//fmt.Printf("%s--> content length: %d\n", strings.Repeat("| ", encodeIndent), len(p.content))
// fmt.Printf("%s--> tag: % X length: %d\n", strings.Repeat("| ", encodeIndent), p.tagBytes, p.length)
// fmt.Printf("%s--> content length: %d\n", strings.Repeat("| ", encodeIndent), len(p.content))
out.Write(p.content)

return nil
Expand All @@ -54,14 +54,14 @@ func ber2der(ber []byte) ([]byte, error) {
if len(ber) == 0 {
return nil, errors.New("ber2der: input ber is empty")
}
//fmt.Printf("--> ber2der: Transcoding %d bytes\n", len(ber))
// fmt.Printf("--> ber2der: Transcoding %d bytes\n", len(ber))
out := new(bytes.Buffer)

obj, _, err := readObject(ber, 0)
if err != nil {
return nil, err
}
obj.EncodeTo(out)
_ = obj.EncodeTo(out)

return out.Bytes(), nil
}
Expand Down Expand Up @@ -98,12 +98,12 @@ func lengthLength(i int) (numBytes int) {
// added to 0x80. The length is encoded in big endian encoding follow after
//
// Examples:
// length | byte 1 | bytes n
// 0 | 0x00 | -
// 120 | 0x78 | -
// 200 | 0x81 | 0xC8
// 500 | 0x82 | 0x01 0xF4
//
// length | byte 1 | bytes n
// 0 | 0x00 | -
// 120 | 0x78 | -
// 200 | 0x81 | 0xC8
// 500 | 0x82 | 0x01 0xF4
func encodeLength(out *bytes.Buffer, length int) (err error) {
if length >= 128 {
l := lengthLength(length)
Expand Down Expand Up @@ -146,7 +146,7 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) {
}
}
// jvehent 20170227: this doesn't appear to be used anywhere...
//tag = tag*128 + ber[offset] - 0x80
// tag = tag*128 + ber[offset] - 0x80
offset++
if offset >= berLen {
return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached")
Expand Down Expand Up @@ -179,17 +179,17 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) {
if numberOfBytes == 4 && (int)(ber[offset]) > 0x7F {
return nil, 0, errors.New("ber2der: BER tag length is negative")
}
if offset + numberOfBytes > berLen {
if offset+numberOfBytes > berLen {
// == condition is not checked here, this allows for a more descreptive error when the parsed length is
// compared with the remaining available bytes (`contentEnd > berLen`)
return nil, 0, errors.New("ber2der: cannot move offset forward, end of ber data reached")
}
if (int)(ber[offset]) == 0x0 && (numberOfBytes == 1 || ber[offset+1] <= 0x7F) {
if (int)(ber[offset]) == 0x0 && (numberOfBytes == 1 || ber[offset+1] <= 0x7F) {
// `numberOfBytes == 1` is an important conditional to avoid a potential out of bounds panic with `ber[offset+1]`
return nil, 0, errors.New("ber2der: BER tag length has leading zero")
}
debugprint("--> (compute length) indicator byte: %x\n", l)
//debugprint("--> (compute length) length bytes: %x\n", ber[offset:offset+numberOfBytes])
// debugprint("--> (compute length) length bytes: %x\n", ber[offset:offset+numberOfBytes])
for i := 0; i < numberOfBytes; i++ {
length = length*256 + (int)(ber[offset])
offset++
Expand All @@ -202,14 +202,14 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) {
if length < 0 {
return nil, 0, errors.New("ber2der: invalid negative value found in BER tag length")
}
//fmt.Printf("--> length : %d\n", length)
// fmt.Printf("--> length : %d\n", length)
contentEnd := offset + length
if contentEnd > berLen {
return nil, 0, errors.New("ber2der: BER tag length is more than available data")
}
debugprint("--> content start : %d\n", offset)
debugprint("--> content end : %d\n", contentEnd)
//debugprint("--> content : %x\n", ber[offset:contentEnd])
// debugprint("--> content : %x\n", ber[offset:contentEnd])
var obj asn1Object
if indefinite && kind == 0 {
return nil, 0, errors.New("ber2der: Indefinite form tag must have constructed encoding")
Expand Down Expand Up @@ -257,13 +257,13 @@ func readObject(ber []byte, offset int) (asn1Object, int, error) {
}

func isIndefiniteTermination(ber []byte, offset int) (bool, error) {
if len(ber) - offset < 2 {
if len(ber)-offset < 2 {
return false, errors.New("ber2der: Invalid BER format")
}

return bytes.Index(ber[offset:], []byte{0x0, 0x0}) == 0, nil
}

func debugprint(format string, a ...interface{}) {
//fmt.Printf(format, a)
// fmt.Printf(format, a)
}
2 changes: 1 addition & 1 deletion ber_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ func TestBer2Der_NestedMultipleIndefinite(t *testing.T) {
if err != nil {
t.Fatalf("ber2der failed with error: %v", err)
}
if bytes.Compare(der, expected) != 0 {
if !bytes.Equal(der, expected) {
t.Errorf("ber2der result did not match.\n\tExpected: % X\n\tActual: % X", expected, der)
}

Expand Down
Loading
Loading