diff --git a/go.mod b/go.mod index eb4d87b..b5e0d4b 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/spf13/pflag v1.0.7 go.uber.org/zap v1.27.0 - software.sslmate.com/src/go-pkcs12 v0.5.0 + software.sslmate.com/src/go-pkcs12 v0.6.0 ) require ( diff --git a/go.sum b/go.sum index 43dc893..41a5dff 100644 --- a/go.sum +++ b/go.sum @@ -24,5 +24,5 @@ golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM= golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -software.sslmate.com/src/go-pkcs12 v0.5.0 h1:EC6R394xgENTpZ4RltKydeDUjtlM5drOYIG9c6TVj2M= -software.sslmate.com/src/go-pkcs12 v0.5.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= +software.sslmate.com/src/go-pkcs12 v0.6.0 h1:f3sQittAeF+pao32Vb+mkli+ZyT+VwKaD014qFGq6oU= +software.sslmate.com/src/go-pkcs12 v0.6.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= diff --git a/vendor/modules.txt b/vendor/modules.txt index af70274..ed2152b 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -30,7 +30,7 @@ go.uber.org/zap/zapcore # golang.org/x/crypto v0.39.0 ## explicit; go 1.23.0 golang.org/x/crypto/pbkdf2 -# software.sslmate.com/src/go-pkcs12 v0.5.0 +# software.sslmate.com/src/go-pkcs12 v0.6.0 ## explicit; go 1.19 software.sslmate.com/src/go-pkcs12 software.sslmate.com/src/go-pkcs12/internal/rc2 diff --git a/vendor/software.sslmate.com/src/go-pkcs12/crypto.go b/vendor/software.sslmate.com/src/go-pkcs12/crypto.go index 673b151..3465787 100644 --- a/vendor/software.sslmate.com/src/go-pkcs12/crypto.go +++ b/vendor/software.sslmate.com/src/go-pkcs12/crypto.go @@ -230,7 +230,8 @@ func pbes2CipherFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher prf = sha512.New case kdfParams.Prf.Algorithm.Equal(oidHmacWithSHA1): prf = sha1.New - case kdfParams.Prf.Algorithm.Equal(asn1.ObjectIdentifier([]int{})): + case kdfParams.Prf.Algorithm == nil: + // Algorithm not specified; defaults to SHA1 according to ASN1 definition prf = sha1.New default: return nil, nil, NotImplementedError("pbes2 prf " + kdfParams.Prf.Algorithm.String() + " is not supported") diff --git a/vendor/software.sslmate.com/src/go-pkcs12/mac.go b/vendor/software.sslmate.com/src/go-pkcs12/mac.go index cce4f9f..23623bb 100644 --- a/vendor/software.sslmate.com/src/go-pkcs12/mac.go +++ b/vendor/software.sslmate.com/src/go-pkcs12/mac.go @@ -12,7 +12,10 @@ import ( "crypto/sha512" "crypto/x509/pkix" "encoding/asn1" + "errors" "hash" + + "golang.org/x/crypto/pbkdf2" ) type macData struct { @@ -27,13 +30,103 @@ type digestInfo struct { Digest []byte } +// PBMAC1 parameters structure from RFC 8018 +// When using PBMAC1, the MAC parameters are derived from the algorithm's Parameters field +// and the macData.MacSalt and macData.Iterations fields are ignored. +type pbmac1Params struct { + Kdf pkix.AlgorithmIdentifier + MacAlg pkix.AlgorithmIdentifier +} + var ( oidSHA1 = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26}) oidSHA256 = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 1}) oidSHA512 = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 3}) + oidPBMAC1 = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 5, 14}) ) +// doPBMAC1 handles PBMAC1 MAC computation using parameters from Algorithm.Parameters +// PBMAC1 (RFC 8018) uses PBKDF2 for key derivation and supports various HMAC algorithms. +// Unlike traditional PKCS#12 MAC algorithms, PBMAC1 gets all its parameters from +// the Algorithm.Parameters field, ignoring macData.MacSalt and macData.Iterations. +func doPBMAC1(algorithm pkix.AlgorithmIdentifier, message, password []byte) ([]byte, error) { + var params pbmac1Params + if err := unmarshal(algorithm.Parameters.FullBytes, ¶ms); err != nil { + return nil, err + } + + // Only PBKDF2 is supported as KDF + if !params.Kdf.Algorithm.Equal(oidPBKDF2) { + return nil, NotImplementedError("PBMAC1 KDF algorithm " + params.Kdf.Algorithm.String() + " is not supported") + } + + var kdfParams pbkdf2Params + if err := unmarshal(params.Kdf.Parameters.FullBytes, &kdfParams); err != nil { + return nil, err + } + + if kdfParams.Salt.Tag != asn1.TagOctetString { + return nil, NotImplementedError("only octet string salts are supported for PBMAC1/PBKDF2") + } + + // Determine PRF function for PBKDF2 + var prf func() hash.Hash + switch { + case kdfParams.Prf.Algorithm.Equal(oidHmacWithSHA256): + prf = sha256.New + case kdfParams.Prf.Algorithm.Equal(oidHmacWithSHA512): + prf = sha512.New + case kdfParams.Prf.Algorithm.Equal(oidHmacWithSHA1): + prf = sha1.New + case kdfParams.Prf.Algorithm == nil: + // Algorithm not specified; defaults to SHA1 according to ASN1 definition + prf = sha1.New + default: + return nil, NotImplementedError("PBMAC1 PRF " + kdfParams.Prf.Algorithm.String() + " is not supported") + } + + // Determine MAC algorithm + var hFn func() hash.Hash + switch { + case params.MacAlg.Algorithm.Equal(oidHmacWithSHA1): + hFn = sha1.New + case params.MacAlg.Algorithm.Equal(oidHmacWithSHA256): + hFn = sha256.New + case params.MacAlg.Algorithm.Equal(oidHmacWithSHA512): + hFn = sha512.New + default: + return nil, NotImplementedError("PBMAC1 MAC algorithm " + params.MacAlg.Algorithm.String() + " is not supported") + } + + // KeyLength is mandatory in RFC 9579 + if kdfParams.KeyLength <= 0 { + return nil, errors.New("pkcs12: PBMAC1 requires explicit KeyLength parameter in PBKDF2 parameters") + } + keyLen := kdfParams.KeyLength + + // Derive key using PBKDF2 + key := pbkdf2.Key(password, kdfParams.Salt.Bytes, kdfParams.Iterations, keyLen, prf) + + // Compute HMAC + mac := hmac.New(hFn, key) + mac.Write(message) + return mac.Sum(nil), nil +} + func doMac(macData *macData, message, password []byte) ([]byte, error) { + // Handle PBMAC1 separately - it uses its own parameters structure from Algorithm.Parameters + // and ignores macData.MacSalt and macData.Iterations fields + if macData.Mac.Algorithm.Algorithm.Equal(oidPBMAC1) { + // PBMAC1 expects UTF-8 passwords (for compatibility; see Erratum 7974), but + // PKCS#12 passwords are BMP strings, so we convert the BMP string back to UTF-8 + originalPassword, err := decodeBMPString(password) + if err != nil { + return nil, err + } + utf8Password := []byte(originalPassword) + return doPBMAC1(macData.Mac.Algorithm, message, utf8Password) + } + var hFn func() hash.Hash var key []byte switch {