From aba5e519a4b0cc27e138d07162b580c0345c9062 Mon Sep 17 00:00:00 2001 From: Kyle Isom Date: Sat, 15 Nov 2025 15:11:07 -0800 Subject: [PATCH] First round of linter cleanups. --- .golangci.yml | 9 ++-- ahash/ahash.go | 37 ++++--------- ahash/ahash_test.go | 44 ++++++++-------- assert/assert.go | 54 ++++++++++--------- backoff/backoff.go | 101 +++++++++++++++--------------------- backoff/backoff_test.go | 22 ++++---- certlib/pkcs7/pkcs7.go | 112 +++++++++++++++++++++++++--------------- go.mod | 6 +-- go.sum | 5 ++ 9 files changed, 200 insertions(+), 190 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 92ccfa5..822bfda 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -65,8 +65,6 @@ linters: - funcorder # checks the order of functions, methods, and constructors - funlen # tool for detection of long functions - gocheckcompilerdirectives # validates go compiler directive comments (//go:) - - gochecknoglobals # checks that no global variables exist - - gochecknoinits # checks that no init functions are present in Go code - gochecksumtype # checks exhaustiveness on Go "sum types" - gocognit # computes and checks the cognitive complexity of functions - goconst # finds repeated strings that could be replaced by a constant @@ -368,7 +366,7 @@ linters: max-func-lines: 0 nolintlint: - # Exclude following linters from requiring an explanation. + # Exclude the following linters from requiring an explanation. # Default: [] allow-no-explanation: [ funlen, gocognit, golines ] # Enable to require an explanation of nonzero length after each nolint directive. @@ -444,8 +442,11 @@ linters: presets: - std-error-handling - common-false-positives - # Excluding configuration per-path, per-linter, per-text and per-source. rules: + - path: 'ahash/ahash.go' + linters: [ staticcheck, gosec ] + - path: 'backoff/backoff_test.go' + linters: [ testpackage ] - source: 'TODO' linters: [ godot ] - text: 'should have a package comment' diff --git a/ahash/ahash.go b/ahash/ahash.go index 25e3b31..3beaa83 100644 --- a/ahash/ahash.go +++ b/ahash/ahash.go @@ -4,8 +4,8 @@ package ahash import ( - "crypto/md5" - "crypto/sha1" + "crypto/md5" // #nosec G505 + "crypto/sha1" // #nosec G501 "crypto/sha256" "crypto/sha512" "errors" @@ -17,34 +17,15 @@ import ( "io" "sort" - "git.wntrmute.dev/kyle/goutils/assert" "golang.org/x/crypto/blake2b" "golang.org/x/crypto/blake2s" - "golang.org/x/crypto/md4" - "golang.org/x/crypto/ripemd160" + "golang.org/x/crypto/md4" // #nosec G506 + "golang.org/x/crypto/ripemd160" // #nosec G507 "golang.org/x/crypto/sha3" + + "git.wntrmute.dev/kyle/goutils/assert" ) -func sha224Slicer(bs []byte) []byte { - sum := sha256.Sum224(bs) - return sum[:] -} - -func sha256Slicer(bs []byte) []byte { - sum := sha256.Sum256(bs) - return sum[:] -} - -func sha384Slicer(bs []byte) []byte { - sum := sha512.Sum384(bs) - return sum[:] -} - -func sha512Slicer(bs []byte) []byte { - sum := sha512.Sum512(bs) - return sum[:] -} - // Hash represents a generic hash function that may or may not be secure. It // satisfies the hash.Hash interface. type Hash struct { @@ -247,17 +228,17 @@ func init() { // HashList returns a sorted list of all the hash algorithms supported by the // package. func HashList() []string { - return hashList[:] + return hashList } // SecureHashList returns a sorted list of all the secure (cryptographic) hash // algorithms supported by the package. func SecureHashList() []string { - return secureHashList[:] + return secureHashList } // InsecureHashList returns a sorted list of all the insecure hash algorithms // supported by the package. func InsecureHashList() []string { - return insecureHashList[:] + return insecureHashList } diff --git a/ahash/ahash_test.go b/ahash/ahash_test.go index afe3e41..9614f0a 100644 --- a/ahash/ahash_test.go +++ b/ahash/ahash_test.go @@ -1,16 +1,18 @@ -package ahash +package ahash_test import ( "bytes" + "encoding/hex" "fmt" "testing" + "git.wntrmute.dev/kyle/goutils/ahash" "git.wntrmute.dev/kyle/goutils/assert" ) func TestSecureHash(t *testing.T) { algo := "sha256" - h, err := New(algo) + h, err := ahash.New(algo) assert.NoErrorT(t, err) assert.BoolT(t, h.IsSecure(), algo+" should be a secure hash") assert.BoolT(t, h.HashAlgo() == algo, "hash returned the wrong HashAlgo") @@ -19,28 +21,28 @@ func TestSecureHash(t *testing.T) { var data []byte var expected = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" - sum, err := Sum(algo, data) + sum, err := ahash.Sum(algo, data) assert.NoErrorT(t, err) - assert.BoolT(t, fmt.Sprintf("%x", sum) == expected, fmt.Sprintf("expected hash %s but have %x", expected, sum)) + assert.BoolT(t, hex.EncodeToString(sum) == expected, fmt.Sprintf("expected hash %s but have %x", expected, sum)) data = []byte("hello, world") buf := bytes.NewBuffer(data) expected = "09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b" - sum, err = SumReader(algo, buf) + sum, err = ahash.SumReader(algo, buf) assert.NoErrorT(t, err) - assert.BoolT(t, fmt.Sprintf("%x", sum) == expected, fmt.Sprintf("expected hash %s but have %x", expected, sum)) + assert.BoolT(t, hex.EncodeToString(sum) == expected, fmt.Sprintf("expected hash %s but have %x", expected, sum)) data = []byte("hello world") _, err = h.Write(data) assert.NoErrorT(t, err) unExpected := "09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b" sum = h.Sum(nil) - assert.BoolT(t, fmt.Sprintf("%x", sum) != unExpected, fmt.Sprintf("hash shouldn't have returned %x", unExpected)) + assert.BoolT(t, hex.EncodeToString(sum) != unExpected, fmt.Sprintf("hash shouldn't have returned %x", unExpected)) } func TestInsecureHash(t *testing.T) { algo := "md5" - h, err := New(algo) + h, err := ahash.New(algo) assert.NoErrorT(t, err) assert.BoolT(t, !h.IsSecure(), algo+" shouldn't be a secure hash") assert.BoolT(t, h.HashAlgo() == algo, "hash returned the wrong HashAlgo") @@ -49,28 +51,28 @@ func TestInsecureHash(t *testing.T) { var data []byte var expected = "d41d8cd98f00b204e9800998ecf8427e" - sum, err := Sum(algo, data) + sum, err := ahash.Sum(algo, data) assert.NoErrorT(t, err) - assert.BoolT(t, fmt.Sprintf("%x", sum) == expected, fmt.Sprintf("expected hash %s but have %x", expected, sum)) + assert.BoolT(t, hex.EncodeToString(sum) == expected, fmt.Sprintf("expected hash %s but have %x", expected, sum)) data = []byte("hello, world") buf := bytes.NewBuffer(data) expected = "e4d7f1b4ed2e42d15898f4b27b019da4" - sum, err = SumReader(algo, buf) + sum, err = ahash.SumReader(algo, buf) assert.NoErrorT(t, err) - assert.BoolT(t, fmt.Sprintf("%x", sum) == expected, fmt.Sprintf("expected hash %s but have %x", expected, sum)) + assert.BoolT(t, hex.EncodeToString(sum) == expected, fmt.Sprintf("expected hash %s but have %x", expected, sum)) data = []byte("hello world") _, err = h.Write(data) assert.NoErrorT(t, err) unExpected := "e4d7f1b4ed2e42d15898f4b27b019da4" sum = h.Sum(nil) - assert.BoolT(t, fmt.Sprintf("%x", sum) != unExpected, fmt.Sprintf("hash shouldn't have returned %x", unExpected)) + assert.BoolT(t, hex.EncodeToString(sum) != unExpected, fmt.Sprintf("hash shouldn't have returned %x", unExpected)) } func TestHash32(t *testing.T) { algo := "crc32-ieee" - h, err := New(algo) + h, err := ahash.New(algo) assert.NoErrorT(t, err) assert.BoolT(t, !h.IsSecure(), algo+" shouldn't be a secure hash") assert.BoolT(t, h.HashAlgo() == algo, "hash returned the wrong HashAlgo") @@ -102,7 +104,7 @@ func TestHash32(t *testing.T) { func TestHash64(t *testing.T) { algo := "crc64" - h, err := New(algo) + h, err := ahash.New(algo) assert.NoErrorT(t, err) assert.BoolT(t, !h.IsSecure(), algo+" shouldn't be a secure hash") assert.BoolT(t, h.HashAlgo() == algo, "hash returned the wrong HashAlgo") @@ -133,9 +135,9 @@ func TestHash64(t *testing.T) { } func TestListLengthSanity(t *testing.T) { - all := HashList() - secure := SecureHashList() - insecure := InsecureHashList() + all := ahash.HashList() + secure := ahash.SecureHashList() + insecure := ahash.InsecureHashList() assert.BoolT(t, len(all) == len(secure)+len(insecure)) } @@ -146,11 +148,11 @@ func TestSumLimitedReader(t *testing.T) { extendedData := bytes.NewBufferString("hello, world! this is an extended message") expected := "09ca7e4eaa6e8ae9c7d261167129184883644d07dfba7cbfbc4c8a2e08360d5b" - hash, err := SumReader("sha256", data) + hash, err := ahash.SumReader("sha256", data) assert.NoErrorT(t, err) - assert.BoolT(t, fmt.Sprintf("%x", hash) == expected, fmt.Sprintf("have hash %x, want %s", hash, expected)) + assert.BoolT(t, hex.EncodeToString(hash) == expected, fmt.Sprintf("have hash %x, want %s", hash, expected)) - extendedHash, err := SumLimitedReader("sha256", extendedData, int64(dataLen)) + extendedHash, err := ahash.SumLimitedReader("sha256", extendedData, int64(dataLen)) assert.NoErrorT(t, err) assert.BoolT(t, bytes.Equal(hash, extendedHash), fmt.Sprintf("have hash %x, want %x", extendedHash, hash)) diff --git a/assert/assert.go b/assert/assert.go index 54d0079..7ab399b 100644 --- a/assert/assert.go +++ b/assert/assert.go @@ -9,6 +9,7 @@ package assert import ( + "errors" "fmt" "os" "runtime" @@ -16,11 +17,13 @@ import ( "testing" ) +const callerSkip = 2 + // NoDebug can be set to true to cause all asserts to be ignored. var NoDebug bool func die(what string, a ...string) { - _, file, line, ok := runtime.Caller(2) + _, file, line, ok := runtime.Caller(callerSkip) if !ok { panic(what) } @@ -31,30 +34,32 @@ func die(what string, a ...string) { s = ": " + s } panic(what + s) - } else { - fmt.Fprintf(os.Stderr, "%s", what) - if len(a) > 0 { - s := strings.Join(a, ", ") - fmt.Fprintln(os.Stderr, ": "+s) - } else { - fmt.Fprintf(os.Stderr, "\n") - } - - fmt.Fprintf(os.Stderr, "\t%s line %d\n", file, line) - - os.Exit(1) } + + fmt.Fprintf(os.Stderr, "%s", what) + if len(a) > 0 { + s := strings.Join(a, ", ") + fmt.Fprintln(os.Stderr, ": "+s) + } else { + fmt.Fprintf(os.Stderr, "\n") + } + + fmt.Fprintf(os.Stderr, "\t%s line %d\n", file, line) + + os.Exit(1) } // Bool asserts that cond is false. // // For example, this would replace -// if x < 0 { -// log.Fatal("x is subzero") -// } +// +// if x < 0 { +// log.Fatal("x is subzero") +// } // // The same assertion would be -// assert.Bool(x, "x is subzero") +// +// assert.Bool(x, "x is subzero") func Bool(cond bool, s ...string) { if NoDebug { return @@ -68,11 +73,12 @@ func Bool(cond bool, s ...string) { // Error asserts that err is not nil, e.g. that an error has occurred. // // For example, -// if err == nil { -// log.Fatal("call to should have failed") -// } -// // becomes -// assert.Error(err, "call to should have failed") +// +// if err == nil { +// log.Fatal("call to should have failed") +// } +// // becomes +// assert.Error(err, "call to should have failed") func Error(err error, s ...string) { if NoDebug { return @@ -100,7 +106,7 @@ func NoError(err error, s ...string) { // ErrorEq asserts that the actual error is the expected error. func ErrorEq(expected, actual error) { - if NoDebug || (expected == actual) { + if NoDebug || (errors.Is(expected, actual)) { return } @@ -155,7 +161,7 @@ func NoErrorT(t *testing.T, err error) { // ErrorEqT compares a pair of errors, calling Fatal on it if they // don't match. func ErrorEqT(t *testing.T, expected, actual error) { - if NoDebug || (expected == actual) { + if NoDebug || (errors.Is(expected, actual)) { return } diff --git a/backoff/backoff.go b/backoff/backoff.go index fd8b513..b284e7d 100644 --- a/backoff/backoff.go +++ b/backoff/backoff.go @@ -10,29 +10,21 @@ // backoff is configured with a maximum duration that will not be // exceeded. // -// The `New` function will attempt to use the system's cryptographic -// random number generator to seed a Go math/rand random number -// source. If this fails, the package will panic on startup. +// This package uses math/rand/v2 for jitter, which is automatically +// seeded from a cryptographically secure source. package backoff import ( - "crypto/rand" - "encoding/binary" - "io" "math" - mrand "math/rand" - "sync" + "math/rand/v2" "time" ) -var prngMu sync.Mutex -var prng *mrand.Rand - // DefaultInterval is used when a Backoff is initialised with a // zero-value Interval. var DefaultInterval = 5 * time.Minute -// DefaultMaxDuration is maximum amount of time that the backoff will +// DefaultMaxDuration is the maximum amount of time that the backoff will // delay for. var DefaultMaxDuration = 6 * time.Hour @@ -50,10 +42,9 @@ type Backoff struct { // interval controls the time step for backing off. interval time.Duration - // noJitter controls whether to use the "Full Jitter" - // improvement to attempt to smooth out spikes in a high - // contention scenario. If noJitter is set to true, no - // jitter will be introduced. + // noJitter controls whether to use the "Full Jitter" improvement to attempt + // to smooth out spikes in a high-contention scenario. If noJitter is set to + // true, no jitter will be introduced. noJitter bool // decay controls the decay of n. If it is non-zero, n is @@ -65,17 +56,17 @@ type Backoff struct { lastTry time.Time } -// New creates a new backoff with the specified max duration and +// New creates a new backoff with the specified maxDuration duration and // interval. Zero values may be used to use the default values. // -// Panics if either max or interval is negative. -func New(max time.Duration, interval time.Duration) *Backoff { - if max < 0 || interval < 0 { - panic("backoff: max or interval is negative") +// Panics if either dMax or interval is negative. +func New(dMax time.Duration, interval time.Duration) *Backoff { + if dMax < 0 || interval < 0 { + panic("backoff: dMax or interval is negative") } b := &Backoff{ - maxDuration: max, + maxDuration: dMax, interval: interval, } b.setup() @@ -84,31 +75,12 @@ func New(max time.Duration, interval time.Duration) *Backoff { // NewWithoutJitter works similarly to New, except that the created // Backoff will not use jitter. -func NewWithoutJitter(max time.Duration, interval time.Duration) *Backoff { - b := New(max, interval) +func NewWithoutJitter(dMax time.Duration, interval time.Duration) *Backoff { + b := New(dMax, interval) b.noJitter = true return b } -func init() { - var buf [8]byte - var n int64 - - _, err := io.ReadFull(rand.Reader, buf[:]) - if err != nil { - panic(err.Error()) - } - - // G115: Intentional uint64->int64 conversion. Overflow is acceptable here - // since math/rand.NewSource accepts any int64 value (positive or negative) - // as a valid seed. The conversion ensures uniform distribution across the - // entire int64 range. - n = int64(binary.LittleEndian.Uint64(buf[:])) // #nosec G115 - - src := mrand.NewSource(n) - prng = mrand.New(src) -} - func (b *Backoff) setup() { if b.interval == 0 { b.interval = DefaultInterval @@ -126,35 +98,44 @@ func (b *Backoff) Duration() time.Duration { b.decayN() - t := b.duration(b.n) + d := b.duration(b.n) if b.n < math.MaxUint64 { b.n++ } if !b.noJitter { - prngMu.Lock() - t = time.Duration(prng.Int63n(int64(t))) - prngMu.Unlock() + d = time.Duration(rand.Int64N(int64(d))) // #nosec G404 } - return t + return d } +const maxN uint64 = 63 + // requires b to be locked. -func (b *Backoff) duration(n uint64) (t time.Duration) { - // Saturate pow - pow := time.Duration(math.MaxInt64) - if n < 63 { - pow = 1 << n +func (b *Backoff) duration(n uint64) time.Duration { + // Use left shift on the underlying integer representation to avoid + // multiplying time.Duration by time.Duration (which is semantically + // incorrect and flagged by linters). + if n >= maxN { + // Saturate when n would overflow a 64-bit shift or exceed maxDuration. + return b.maxDuration } - t = b.interval * pow - if t/pow != b.interval || t > b.maxDuration { - t = b.maxDuration + // Calculate 2^n * interval using a shift. Detect overflow by checking + // for sign change or monotonicity loss and clamp to maxDuration. + shifted := b.interval << n + if shifted < 0 || shifted < b.interval { + // Overflow occurred during the shift; clamp to maxDuration. + return b.maxDuration } - return + if shifted > b.maxDuration { + return b.maxDuration + } + + return shifted } // Reset resets the attempt counter of a backoff. @@ -178,7 +159,7 @@ func (b *Backoff) SetDecay(decay time.Duration) { b.decay = decay } -// requires b to be locked +// requires b to be locked. func (b *Backoff) decayN() { if b.decay == 0 { return @@ -190,7 +171,9 @@ func (b *Backoff) decayN() { } lastDuration := b.duration(b.n - 1) - decayed := time.Since(b.lastTry) > lastDuration+b.decay + // Reset when the elapsed time is at least the previous backoff plus decay. + // Using ">=" avoids boundary flakiness in tests and real usage. + decayed := time.Since(b.lastTry) >= lastDuration+b.decay b.lastTry = time.Now() if !decayed { diff --git a/backoff/backoff_test.go b/backoff/backoff_test.go index 21cc8cb..1c62afc 100644 --- a/backoff/backoff_test.go +++ b/backoff/backoff_test.go @@ -9,7 +9,7 @@ import ( // If given New with 0's and no jitter, ensure that certain invariants are met: // -// - the default max duration and interval should be used +// - the default maxDuration duration and interval should be used // - noJitter should be true // - the RNG should not be initialised // - the first duration should be equal to the default interval @@ -17,7 +17,11 @@ func TestDefaults(t *testing.T) { b := NewWithoutJitter(0, 0) if b.maxDuration != DefaultMaxDuration { - t.Fatalf("expected new backoff to use the default max duration (%s), but have %s", DefaultMaxDuration, b.maxDuration) + t.Fatalf( + "expected new backoff to use the default maxDuration duration (%s), but have %s", + DefaultMaxDuration, + b.maxDuration, + ) } if b.interval != DefaultInterval { @@ -48,7 +52,7 @@ func TestSetup(t *testing.T) { func TestTries(t *testing.T) { b := NewWithoutJitter(5, 1) - for i := uint64(0); i < 3; i++ { + for i := range uint64(3) { if b.n != i { t.Fatalf("want tries=%d, have tries=%d", i, b.n) } @@ -73,7 +77,7 @@ func TestTries(t *testing.T) { func TestReset(t *testing.T) { const iter = 10 b := New(1000, 1) - for i := 0; i < iter; i++ { + for range iter { _ = b.Duration() } @@ -88,17 +92,17 @@ func TestReset(t *testing.T) { } const decay = 5 * time.Millisecond -const max = 10 * time.Millisecond +const maxDuration = 10 * time.Millisecond const interval = time.Millisecond func TestDecay(t *testing.T) { const iter = 10 - b := NewWithoutJitter(max, 1) + b := NewWithoutJitter(maxDuration, 1) b.SetDecay(decay) var backoff time.Duration - for i := 0; i < iter; i++ { + for range iter { backoff = b.Duration() } @@ -127,7 +131,7 @@ func TestDecaySaturation(t *testing.T) { b.SetDecay(decay) var duration time.Duration - for i := 0; i <= 2; i++ { + for range 3 { duration = b.Duration() } @@ -145,7 +149,7 @@ func TestDecaySaturation(t *testing.T) { } func ExampleBackoff_SetDecay() { - b := NewWithoutJitter(max, interval) + b := NewWithoutJitter(maxDuration, interval) b.SetDecay(decay) // try 0 diff --git a/certlib/pkcs7/pkcs7.go b/certlib/pkcs7/pkcs7.go index bfea534..b4fbdfb 100644 --- a/certlib/pkcs7/pkcs7.go +++ b/certlib/pkcs7/pkcs7.go @@ -158,59 +158,87 @@ type EncryptedContentInfo struct { EncryptedContent []byte `asn1:"tag:0,optional"` } +func unmarshalInit(raw []byte) (init initPKCS7, err error) { + _, err = asn1.Unmarshal(raw, &init) + if err != nil { + return initPKCS7{}, certerr.ParsingError(certerr.ErrorSourceCertificate, err) + } + return init, nil +} + +func populateData(msg *PKCS7, content asn1.RawValue) error { + msg.ContentInfo = "Data" + _, err := asn1.Unmarshal(content.Bytes, &msg.Content.Data) + if err != nil { + return certerr.ParsingError(certerr.ErrorSourceCertificate, err) + } + return nil +} + +func populateSignedData(msg *PKCS7, contentBytes []byte) error { + msg.ContentInfo = "SignedData" + var sd signedData + if _, err := asn1.Unmarshal(contentBytes, &sd); err != nil { + return certerr.ParsingError(certerr.ErrorSourceCertificate, err) + } + if len(sd.Certificates.Bytes) != 0 { + certs, err := x509.ParseCertificates(sd.Certificates.Bytes) + if err != nil { + return certerr.ParsingError(certerr.ErrorSourceCertificate, err) + } + msg.Content.SignedData.Certificates = certs + } + if len(sd.Crls.Bytes) != 0 { + crl, err := x509.ParseRevocationList(sd.Crls.Bytes) + if err != nil { + return certerr.ParsingError(certerr.ErrorSourceCertificate, err) + } + msg.Content.SignedData.Crl = crl + } + msg.Content.SignedData.Version = sd.Version + msg.Content.SignedData.Raw = contentBytes + return nil +} + +func populateEncryptedData(msg *PKCS7, contentBytes []byte) error { + msg.ContentInfo = "EncryptedData" + var ed EncryptedData + if _, err := asn1.Unmarshal(contentBytes, &ed); err != nil { + return certerr.ParsingError(certerr.ErrorSourceCertificate, err) + } + if ed.Version != 0 { + return certerr.ParsingError(certerr.ErrorSourceCertificate, errors.New("only PKCS #7 encryptedData version 0 is supported")) + } + msg.Content.EncryptedData = ed + return nil +} + // ParsePKCS7 attempts to parse the DER encoded bytes of a // PKCS7 structure. func ParsePKCS7(raw []byte) (msg *PKCS7, err error) { - var pkcs7 initPKCS7 - _, err = asn1.Unmarshal(raw, &pkcs7) + pkcs7, err := unmarshalInit(raw) if err != nil { - return nil, certerr.ParsingError(certerr.ErrorSourceCertificate, err) + return nil, err } msg = new(PKCS7) msg.Raw = pkcs7.Raw msg.ContentInfo = pkcs7.ContentType.String() - switch { - case msg.ContentInfo == ObjIDData: - msg.ContentInfo = "Data" - _, err = asn1.Unmarshal(pkcs7.Content.Bytes, &msg.Content.Data) - if err != nil { - return nil, certerr.ParsingError(certerr.ErrorSourceCertificate, err) - } - case msg.ContentInfo == ObjIDSignedData: - msg.ContentInfo = "SignedData" - var signedData signedData - _, err = asn1.Unmarshal(pkcs7.Content.Bytes, &signedData) - if err != nil { - return nil, certerr.ParsingError(certerr.ErrorSourceCertificate, err) - } - if len(signedData.Certificates.Bytes) != 0 { - msg.Content.SignedData.Certificates, err = x509.ParseCertificates(signedData.Certificates.Bytes) - if err != nil { - return nil, certerr.ParsingError(certerr.ErrorSourceCertificate, err) - } - } - if len(signedData.Crls.Bytes) != 0 { - msg.Content.SignedData.Crl, err = x509.ParseRevocationList(signedData.Crls.Bytes) - if err != nil { - return nil, certerr.ParsingError(certerr.ErrorSourceCertificate, err) - } - } - msg.Content.SignedData.Version = signedData.Version - msg.Content.SignedData.Raw = pkcs7.Content.Bytes - case msg.ContentInfo == ObjIDEncryptedData: - msg.ContentInfo = "EncryptedData" - var encryptedData EncryptedData - _, err = asn1.Unmarshal(pkcs7.Content.Bytes, &encryptedData) - if err != nil { - return nil, certerr.ParsingError(certerr.ErrorSourceCertificate, err) - } - if encryptedData.Version != 0 { - return nil, certerr.ParsingError(certerr.ErrorSourceCertificate, errors.New("only PKCS #7 encryptedData version 0 is supported")) - } - msg.Content.EncryptedData = encryptedData + switch msg.ContentInfo { + case ObjIDData: + if err := populateData(msg, pkcs7.Content); err != nil { + return nil, err + } + case ObjIDSignedData: + if err := populateSignedData(msg, pkcs7.Content.Bytes); err != nil { + return nil, err + } + case ObjIDEncryptedData: + if err := populateEncryptedData(msg, pkcs7.Content.Bytes); err != nil { + return nil, err + } default: return nil, certerr.ParsingError(certerr.ErrorSourceCertificate, errors.New("only PKCS# 7 content of type data, signed data or encrypted data can be parsed")) } diff --git a/go.mod b/go.mod index ea0518d..fa9890a 100644 --- a/go.mod +++ b/go.mod @@ -1,14 +1,14 @@ module git.wntrmute.dev/kyle/goutils -go 1.22 +go 1.24.0 require ( github.com/hashicorp/go-syslog v1.0.0 github.com/kr/text v0.2.0 github.com/pkg/errors v0.9.1 github.com/pkg/sftp v1.12.0 - golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b - golang.org/x/sys v0.0.0-20220412211240-33da011f77ad + golang.org/x/crypto v0.44.0 + golang.org/x/sys v0.38.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/go.sum b/go.sum index e69db8b..422c06f 100644 --- a/go.sum +++ b/go.sum @@ -27,12 +27,17 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b h1:Qwe1rC8PSniVfAFPFJeyUkB+zcysC3RgJBAGk7eqBEU= golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.44.0 h1:A97SsFvM3AIwEEmTBiaxPPTYpDC47w720rdiiUvgoAU= +golang.org/x/crypto v0.44.0/go.mod h1:013i+Nw79BMiQiMsOPcVCB5ZIJbYkerPrGnOa00tvmc= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=