pax_global_header00006660000000000000000000000064142265541610014520gustar00rootroot0000000000000052 comment=18dc7b9430c99e109671045dbd9889389c8072d7 go-pkcs12-0.2.0/000077500000000000000000000000001422655416100132255ustar00rootroot00000000000000go-pkcs12-0.2.0/.gitattributes000066400000000000000000000005311422655416100161170ustar00rootroot00000000000000# Treat all files in this repo as binary, with no git magic updating # line endings. Windows users contributing to Go will need to use a # modern version of git and editors capable of LF line endings. # # We'll prevent accidental CRLF line endings from entering the repo # via the git-review gofmt checks. # # See golang.org/issue/9281 * -text go-pkcs12-0.2.0/.gitignore000066400000000000000000000001241422655416100152120ustar00rootroot00000000000000# Add no patterns to .hgignore except for files generated by the build. last-change go-pkcs12-0.2.0/LICENSE000066400000000000000000000030111422655416100142250ustar00rootroot00000000000000Copyright (c) 2015, 2018, 2019 Opsmate, Inc. All rights reserved. Copyright (c) 2009 The Go Authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. go-pkcs12-0.2.0/README.md000066400000000000000000000023061422655416100145050ustar00rootroot00000000000000# package pkcs12 [![Documentation](https://pkg.go.dev/badge/software.sslmate.com/src/go-pkcs12)](https://pkg.go.dev/software.sslmate.com/src/go-pkcs12) import "software.sslmate.com/src/go-pkcs12" Package pkcs12 implements some of PKCS#12 (also known as P12 or PFX). It is intended for decoding DER-encoded P12/PFX files for use with the `crypto/tls` package, and for encoding P12/PFX files for use by legacy applications which do not support newer formats. Since PKCS#12 uses weak encryption primitives, it SHOULD NOT be used for new applications. Note that only DER-encoded PKCS#12 files are supported, even though PKCS#12 allows BER encoding. This is because encoding/asn1 only supports DER. This package is forked from `golang.org/x/crypto/pkcs12`, which is frozen. The implementation is distilled from https://tools.ietf.org/html/rfc7292 and referenced documents. ## Import Path Note that although the source code and issue tracker for this package are hosted on GitHub, the import path is: software.sslmate.com/src/go-pkcs12 Please be sure to use this path when you `go get` and `import` this package. ## Report Issues / Send Patches Open an issue or PR at https://github.com/SSLMate/go-pkcs12 go-pkcs12-0.2.0/bmp-string.go000066400000000000000000000033341422655416100156410ustar00rootroot00000000000000// Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package pkcs12 import ( "errors" "unicode/utf16" ) // bmpStringZeroTerminated returns s encoded in UCS-2 with a zero terminator. func bmpStringZeroTerminated(s string) ([]byte, error) { // References: // https://tools.ietf.org/html/rfc7292#appendix-B.1 // The above RFC provides the info that BMPStrings are NULL terminated. ret, err := bmpString(s) if err != nil { return nil, err } return append(ret, 0, 0), nil } // bmpString returns s encoded in UCS-2 func bmpString(s string) ([]byte, error) { // References: // https://tools.ietf.org/html/rfc7292#appendix-B.1 // https://en.wikipedia.org/wiki/Plane_(Unicode)#Basic_Multilingual_Plane // - non-BMP characters are encoded in UTF 16 by using a surrogate pair of 16-bit codes // EncodeRune returns 0xfffd if the rune does not need special encoding ret := make([]byte, 0, 2*len(s)+2) for _, r := range s { if t, _ := utf16.EncodeRune(r); t != 0xfffd { return nil, errors.New("pkcs12: string contains characters that cannot be encoded in UCS-2") } ret = append(ret, byte(r/256), byte(r%256)) } return ret, nil } func decodeBMPString(bmpString []byte) (string, error) { if len(bmpString)%2 != 0 { return "", errors.New("pkcs12: odd-length BMP string") } // strip terminator if present if l := len(bmpString); l >= 2 && bmpString[l-1] == 0 && bmpString[l-2] == 0 { bmpString = bmpString[:l-2] } s := make([]uint16, 0, len(bmpString)/2) for len(bmpString) > 0 { s = append(s, uint16(bmpString[0])<<8+uint16(bmpString[1])) bmpString = bmpString[2:] } return string(utf16.Decode(s)), nil } go-pkcs12-0.2.0/bmp-string_test.go000066400000000000000000000040311422655416100166730ustar00rootroot00000000000000// Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package pkcs12 import ( "bytes" "encoding/hex" "testing" ) var bmpStringTests = []struct { in string expectedHex string zeroTerminated bool shouldFail bool }{ {"", "0000", true, false}, {"", "", false, false}, // Example from https://tools.ietf.org/html/rfc7292#appendix-B. {"Beavis", "0042006500610076006900730000", true, false}, {"Beavis", "004200650061007600690073", false, false}, // Some characters from the "Letterlike Symbols Unicode block". {"\u2115 - Double-struck N", "21150020002d00200044006f00750062006c0065002d00730074007200750063006b0020004e0000", true, false}, {"\u2115 - Double-struck N", "21150020002d00200044006f00750062006c0065002d00730074007200750063006b0020004e", false, false}, // any character outside the BMP should trigger an error. {"\U0001f000 East wind (Mahjong)", "", true, true}, {"\U0001f000 East wind (Mahjong)", "", false, true}, } func TestBMPString(t *testing.T) { for i, test := range bmpStringTests { expected, err := hex.DecodeString(test.expectedHex) if err != nil { t.Fatalf("#%d: failed to decode expectation", i) } var out []byte if(test.zeroTerminated) { out, err = bmpStringZeroTerminated(test.in) } else { out, err = bmpString(test.in) } if err == nil && test.shouldFail { t.Errorf("#%d: expected to fail, but produced %x", i, out) continue } if err != nil && !test.shouldFail { t.Errorf("#%d: failed unexpectedly: %s", i, err) continue } if !test.shouldFail { if !bytes.Equal(out, expected) { t.Errorf("#%d: expected %s, got %x", i, test.expectedHex, out) continue } roundTrip, err := decodeBMPString(out) if err != nil { t.Errorf("#%d: decoding output gave an error: %s", i, err) continue } if roundTrip != test.in { t.Errorf("#%d: decoding output resulted in %q, but it should have been %q", i, roundTrip, test.in) continue } } } } go-pkcs12-0.2.0/crypto.go000066400000000000000000000200231422655416100150710ustar00rootroot00000000000000// Copyright 2015, 2018, 2019 Opsmate, Inc. All rights reserved. // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package pkcs12 import ( "bytes" "crypto/aes" "crypto/cipher" "crypto/des" "crypto/sha1" "crypto/sha256" "crypto/x509/pkix" "encoding/asn1" "errors" "hash" "golang.org/x/crypto/pbkdf2" "software.sslmate.com/src/go-pkcs12/internal/rc2" ) var ( oidPBEWithSHAAnd3KeyTripleDESCBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3}) oidPBEWithSHAAnd40BitRC2CBC = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 6}) oidPBES2 = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 5, 13}) oidPBKDF2 = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 5, 12}) oidHmacWithSHA1 = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 2, 7}) oidHmacWithSHA256 = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 2, 9}) oidAES256CBC = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 1, 42}) ) // pbeCipher is an abstraction of a PKCS#12 cipher. type pbeCipher interface { // create returns a cipher.Block given a key. create(key []byte) (cipher.Block, error) // deriveKey returns a key derived from the given password and salt. deriveKey(salt, password []byte, iterations int) []byte // deriveKey returns an IV derived from the given password and salt. deriveIV(salt, password []byte, iterations int) []byte } type shaWithTripleDESCBC struct{} func (shaWithTripleDESCBC) create(key []byte) (cipher.Block, error) { return des.NewTripleDESCipher(key) } func (shaWithTripleDESCBC) deriveKey(salt, password []byte, iterations int) []byte { return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 24) } func (shaWithTripleDESCBC) deriveIV(salt, password []byte, iterations int) []byte { return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8) } type shaWith40BitRC2CBC struct{} func (shaWith40BitRC2CBC) create(key []byte) (cipher.Block, error) { return rc2.New(key, len(key)*8) } func (shaWith40BitRC2CBC) deriveKey(salt, password []byte, iterations int) []byte { return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 1, 5) } func (shaWith40BitRC2CBC) deriveIV(salt, password []byte, iterations int) []byte { return pbkdf(sha1Sum, 20, 64, salt, password, iterations, 2, 8) } type pbeParams struct { Salt []byte Iterations int } func pbeCipherFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.Block, []byte, error) { var cipherType pbeCipher switch { case algorithm.Algorithm.Equal(oidPBEWithSHAAnd3KeyTripleDESCBC): cipherType = shaWithTripleDESCBC{} case algorithm.Algorithm.Equal(oidPBEWithSHAAnd40BitRC2CBC): cipherType = shaWith40BitRC2CBC{} case algorithm.Algorithm.Equal(oidPBES2): // rfc7292#appendix-B.1 (the original PKCS#12 PBE) requires passwords formatted as BMPStrings. // However, rfc8018#section-3 recommends that the password for PBES2 follow ASCII or UTF-8. // This is also what Windows expects. // Therefore, we convert the password to UTF-8. originalPassword, err := decodeBMPString(password) if err != nil { return nil, nil, err } utf8Password := []byte(originalPassword) return pbes2CipherFor(algorithm, utf8Password) default: return nil, nil, NotImplementedError("algorithm " + algorithm.Algorithm.String() + " is not supported") } var params pbeParams if err := unmarshal(algorithm.Parameters.FullBytes, ¶ms); err != nil { return nil, nil, err } key := cipherType.deriveKey(params.Salt, password, params.Iterations) iv := cipherType.deriveIV(params.Salt, password, params.Iterations) block, err := cipherType.create(key) if err != nil { return nil, nil, err } return block, iv, nil } func pbDecrypterFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.BlockMode, int, error) { block, iv, err := pbeCipherFor(algorithm, password) if err != nil { return nil, 0, err } return cipher.NewCBCDecrypter(block, iv), block.BlockSize(), nil } func pbDecrypt(info decryptable, password []byte) (decrypted []byte, err error) { cbc, blockSize, err := pbDecrypterFor(info.Algorithm(), password) if err != nil { return nil, err } encrypted := info.Data() if len(encrypted) == 0 { return nil, errors.New("pkcs12: empty encrypted data") } if len(encrypted)%blockSize != 0 { return nil, errors.New("pkcs12: input is not a multiple of the block size") } decrypted = make([]byte, len(encrypted)) cbc.CryptBlocks(decrypted, encrypted) psLen := int(decrypted[len(decrypted)-1]) if psLen == 0 || psLen > blockSize { return nil, ErrDecryption } if len(decrypted) < psLen { return nil, ErrDecryption } ps := decrypted[len(decrypted)-psLen:] decrypted = decrypted[:len(decrypted)-psLen] if bytes.Compare(ps, bytes.Repeat([]byte{byte(psLen)}, psLen)) != 0 { return nil, ErrDecryption } return } // PBES2-params ::= SEQUENCE { // keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}}, // encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} // } type pbes2Params struct { Kdf pkix.AlgorithmIdentifier EncryptionScheme pkix.AlgorithmIdentifier } // PBKDF2-params ::= SEQUENCE { // salt CHOICE { // specified OCTET STRING, // otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}} // }, // iterationCount INTEGER (1..MAX), // keyLength INTEGER (1..MAX) OPTIONAL, // prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT // algid-hmacWithSHA1 // } type pbkdf2Params struct { Salt asn1.RawValue Iterations int KeyLength int `asn1:"optional"` Prf pkix.AlgorithmIdentifier } func pbes2CipherFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.Block, []byte, error) { var params pbes2Params if err := unmarshal(algorithm.Parameters.FullBytes, ¶ms); err != nil { return nil, nil, err } if !params.Kdf.Algorithm.Equal(oidPBKDF2) { return nil, nil, NotImplementedError("kdf algorithm " + params.Kdf.Algorithm.String() + " is not supported") } var kdfParams pbkdf2Params if err := unmarshal(params.Kdf.Parameters.FullBytes, &kdfParams); err != nil { return nil, nil, err } if kdfParams.Salt.Tag != asn1.TagOctetString { return nil, nil, errors.New("pkcs12: only octet string salts are supported for pbkdf2") } var prf func() hash.Hash switch { case kdfParams.Prf.Algorithm.Equal(oidHmacWithSHA256): prf = sha256.New case kdfParams.Prf.Algorithm.Equal(oidHmacWithSHA1): prf = sha1.New case kdfParams.Prf.Algorithm.Equal(asn1.ObjectIdentifier([]int{})): prf = sha1.New } key := pbkdf2.Key(password, kdfParams.Salt.Bytes, kdfParams.Iterations, 32, prf) iv := params.EncryptionScheme.Parameters.Bytes var block cipher.Block switch { case params.EncryptionScheme.Algorithm.Equal(oidAES256CBC): b, err := aes.NewCipher(key) if err != nil { return nil, nil, err } block = b default: return nil, nil, NotImplementedError("pbes2 algorithm " + params.EncryptionScheme.Algorithm.String() + " is not supported") } return block, iv, nil } // decryptable abstracts an object that contains ciphertext. type decryptable interface { Algorithm() pkix.AlgorithmIdentifier Data() []byte } func pbEncrypterFor(algorithm pkix.AlgorithmIdentifier, password []byte) (cipher.BlockMode, int, error) { block, iv, err := pbeCipherFor(algorithm, password) if err != nil { return nil, 0, err } return cipher.NewCBCEncrypter(block, iv), block.BlockSize(), nil } func pbEncrypt(info encryptable, decrypted []byte, password []byte) error { cbc, blockSize, err := pbEncrypterFor(info.Algorithm(), password) if err != nil { return err } psLen := blockSize - len(decrypted)%blockSize encrypted := make([]byte, len(decrypted)+psLen) copy(encrypted[:len(decrypted)], decrypted) copy(encrypted[len(decrypted):], bytes.Repeat([]byte{byte(psLen)}, psLen)) cbc.CryptBlocks(encrypted, encrypted) info.SetData(encrypted) return nil } // encryptable abstracts a object that contains ciphertext. type encryptable interface { Algorithm() pkix.AlgorithmIdentifier SetData([]byte) } go-pkcs12-0.2.0/crypto_test.go000066400000000000000000000121621422655416100161350ustar00rootroot00000000000000// Copyright 2015, 2018, 2019 Opsmate, Inc. All rights reserved. // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package pkcs12 import ( "bytes" "crypto/x509/pkix" "encoding/asn1" "testing" ) var sha1WithTripleDES = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3}) func TestPbDecrypterFor(t *testing.T) { params, _ := asn1.Marshal(pbeParams{ Salt: []byte{1, 2, 3, 4, 5, 6, 7, 8}, Iterations: 2048, }) alg := pkix.AlgorithmIdentifier{ Algorithm: asn1.ObjectIdentifier([]int{1, 2, 3}), Parameters: asn1.RawValue{ FullBytes: params, }, } pass, _ := bmpStringZeroTerminated("Sesame open") _, _, err := pbDecrypterFor(alg, pass) if _, ok := err.(NotImplementedError); !ok { t.Errorf("expected not implemented error, got: %T %s", err, err) } alg.Algorithm = sha1WithTripleDES cbc, blockSize, err := pbDecrypterFor(alg, pass) if err != nil { t.Errorf("unexpected error from pbDecrypterFor %v", err) } if blockSize != 8 { t.Errorf("unexpected block size %d, wanted 8", blockSize) } plaintext := []byte{1, 2, 3, 4, 5, 6, 7, 8} expectedCiphertext := []byte{185, 73, 135, 249, 137, 1, 122, 247} ciphertext := make([]byte, len(plaintext)) cbc.CryptBlocks(ciphertext, plaintext) if bytes.Compare(ciphertext, expectedCiphertext) != 0 { t.Errorf("bad ciphertext, got %x but wanted %x", ciphertext, expectedCiphertext) } } func TestPbEncrypterFor(t *testing.T) { params, _ := asn1.Marshal(pbeParams{ Salt: []byte{1, 2, 3, 4, 5, 6, 7, 8}, Iterations: 2048, }) alg := pkix.AlgorithmIdentifier{ Algorithm: asn1.ObjectIdentifier([]int{1, 2, 3}), Parameters: asn1.RawValue{ FullBytes: params, }, } pass, _ := bmpStringZeroTerminated("Sesame open") _, _, err := pbEncrypterFor(alg, pass) if _, ok := err.(NotImplementedError); !ok { t.Errorf("expected not implemented error, got: %T %s", err, err) } alg.Algorithm = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3}) cbc, _, err := pbEncrypterFor(alg, pass) if err != nil { t.Errorf("err: %v", err) } expectedM := []byte{1, 2, 3, 4, 5, 6, 7, 8} M := []byte{185, 73, 135, 249, 137, 1, 122, 247} cbc.CryptBlocks(M, M) if bytes.Compare(M, expectedM) != 0 { t.Errorf("expected M to be '%d', but found '%d", expectedM, M) } } var pbDecryptTests = []struct { in []byte expected []byte expectedError error }{ { []byte("\x33\x73\xf3\x9f\xda\x49\xae\xfc\xa0\x9a\xdf\x5a\x58\xa0\xea\x46"), // 7 padding bytes []byte("A secret!"), nil, }, { []byte("\x33\x73\xf3\x9f\xda\x49\xae\xfc\x96\x24\x2f\x71\x7e\x32\x3f\xe7"), // 8 padding bytes []byte("A secret"), nil, }, { []byte("\x35\x0c\xc0\x8d\xab\xa9\x5d\x30\x7f\x9a\xec\x6a\xd8\x9b\x9c\xd9"), // 9 padding bytes, incorrect nil, ErrDecryption, }, { []byte("\xb2\xf9\x6e\x06\x60\xae\x20\xcf\x08\xa0\x7b\xd9\x6b\x20\xef\x41"), // incorrect padding bytes: [ ... 0x04 0x02 ] nil, ErrDecryption, }, } func TestPbDecrypt(t *testing.T) { for i, test := range pbDecryptTests { decryptable := testDecryptable{ data: test.in, algorithm: pkix.AlgorithmIdentifier{ Algorithm: sha1WithTripleDES, Parameters: pbeParams{ Salt: []byte("\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8"), Iterations: 4096, }.RawASN1(), }, } password, _ := bmpStringZeroTerminated("sesame") plaintext, err := pbDecrypt(decryptable, password) if err != test.expectedError { t.Errorf("#%d: got error %q, but wanted %q", i, err, test.expectedError) continue } if !bytes.Equal(plaintext, test.expected) { t.Errorf("#%d: got %x, but wanted %x", i, plaintext, test.expected) } } } func TestPbEncrypt(t *testing.T) { tests := [][]byte{ []byte("A secret!"), []byte("A secret"), } expected := [][]byte{ []byte("\x33\x73\xf3\x9f\xda\x49\xae\xfc\xa0\x9a\xdf\x5a\x58\xa0\xea\x46"), // 7 padding bytes []byte("\x33\x73\xf3\x9f\xda\x49\xae\xfc\x96\x24\x2f\x71\x7e\x32\x3f\xe7"), // 8 padding bytes } for i, c := range tests { td := testDecryptable{ algorithm: pkix.AlgorithmIdentifier{ Algorithm: asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 1, 3}), // SHA1/3TDES Parameters: pbeParams{ Salt: []byte("\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8"), Iterations: 4096, }.RawASN1(), }, } p, _ := bmpStringZeroTerminated("sesame") err := pbEncrypt(&td, c, p) if err != nil { t.Errorf("error encrypting %d: %v", c, err) } if bytes.Compare(td.data, expected[i]) != 0 { t.Errorf("expected %d to be encrypted to %d, but found %d", c, expected[i], td.data) } } } type testDecryptable struct { data []byte algorithm pkix.AlgorithmIdentifier } func (d testDecryptable) Algorithm() pkix.AlgorithmIdentifier { return d.algorithm } func (d testDecryptable) Data() []byte { return d.data } func (d *testDecryptable) SetData(data []byte) { d.data = data } func (params pbeParams) RawASN1() (raw asn1.RawValue) { asn1Bytes, err := asn1.Marshal(params) if err != nil { panic(err) } _, err = asn1.Unmarshal(asn1Bytes, &raw) if err != nil { panic(err) } return } go-pkcs12-0.2.0/errors.go000066400000000000000000000013571422655416100150760ustar00rootroot00000000000000// Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package pkcs12 import "errors" var ( // ErrDecryption represents a failure to decrypt the input. ErrDecryption = errors.New("pkcs12: decryption error, incorrect padding") // ErrIncorrectPassword is returned when an incorrect password is detected. // Usually, P12/PFX data is signed to be able to verify the password. ErrIncorrectPassword = errors.New("pkcs12: decryption password incorrect") ) // NotImplementedError indicates that the input is not currently supported. type NotImplementedError string func (e NotImplementedError) Error() string { return "pkcs12: " + string(e) } go-pkcs12-0.2.0/go.mod000066400000000000000000000001771422655416100143400ustar00rootroot00000000000000module software.sslmate.com/src/go-pkcs12 go 1.15 require golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 // indirect go-pkcs12-0.2.0/go.sum000066400000000000000000000035161422655416100143650ustar00rootroot00000000000000golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g= golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o= golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= go-pkcs12-0.2.0/internal/000077500000000000000000000000001422655416100150415ustar00rootroot00000000000000go-pkcs12-0.2.0/internal/rc2/000077500000000000000000000000001422655416100155275ustar00rootroot00000000000000go-pkcs12-0.2.0/internal/rc2/bench_test.go000066400000000000000000000010571422655416100201770ustar00rootroot00000000000000// Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package rc2 import ( "testing" ) func BenchmarkEncrypt(b *testing.B) { r, _ := New([]byte{0, 0, 0, 0, 0, 0, 0, 0}, 64) b.ResetTimer() var src [8]byte for i := 0; i < b.N; i++ { r.Encrypt(src[:], src[:]) } } func BenchmarkDecrypt(b *testing.B) { r, _ := New([]byte{0, 0, 0, 0, 0, 0, 0, 0}, 64) b.ResetTimer() var src [8]byte for i := 0; i < b.N; i++ { r.Decrypt(src[:], src[:]) } } go-pkcs12-0.2.0/internal/rc2/rc2.go000066400000000000000000000142721422655416100165520ustar00rootroot00000000000000// Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package rc2 implements the RC2 cipher /* https://www.ietf.org/rfc/rfc2268.txt http://people.csail.mit.edu/rivest/pubs/KRRR98.pdf This code is licensed under the MIT license. */ package rc2 import ( "crypto/cipher" "encoding/binary" ) // The rc2 block size in bytes const BlockSize = 8 type rc2Cipher struct { k [64]uint16 } // New returns a new rc2 cipher with the given key and effective key length t1 func New(key []byte, t1 int) (cipher.Block, error) { // TODO(dgryski): error checking for key length return &rc2Cipher{ k: expandKey(key, t1), }, nil } func (*rc2Cipher) BlockSize() int { return BlockSize } var piTable = [256]byte{ 0xd9, 0x78, 0xf9, 0xc4, 0x19, 0xdd, 0xb5, 0xed, 0x28, 0xe9, 0xfd, 0x79, 0x4a, 0xa0, 0xd8, 0x9d, 0xc6, 0x7e, 0x37, 0x83, 0x2b, 0x76, 0x53, 0x8e, 0x62, 0x4c, 0x64, 0x88, 0x44, 0x8b, 0xfb, 0xa2, 0x17, 0x9a, 0x59, 0xf5, 0x87, 0xb3, 0x4f, 0x13, 0x61, 0x45, 0x6d, 0x8d, 0x09, 0x81, 0x7d, 0x32, 0xbd, 0x8f, 0x40, 0xeb, 0x86, 0xb7, 0x7b, 0x0b, 0xf0, 0x95, 0x21, 0x22, 0x5c, 0x6b, 0x4e, 0x82, 0x54, 0xd6, 0x65, 0x93, 0xce, 0x60, 0xb2, 0x1c, 0x73, 0x56, 0xc0, 0x14, 0xa7, 0x8c, 0xf1, 0xdc, 0x12, 0x75, 0xca, 0x1f, 0x3b, 0xbe, 0xe4, 0xd1, 0x42, 0x3d, 0xd4, 0x30, 0xa3, 0x3c, 0xb6, 0x26, 0x6f, 0xbf, 0x0e, 0xda, 0x46, 0x69, 0x07, 0x57, 0x27, 0xf2, 0x1d, 0x9b, 0xbc, 0x94, 0x43, 0x03, 0xf8, 0x11, 0xc7, 0xf6, 0x90, 0xef, 0x3e, 0xe7, 0x06, 0xc3, 0xd5, 0x2f, 0xc8, 0x66, 0x1e, 0xd7, 0x08, 0xe8, 0xea, 0xde, 0x80, 0x52, 0xee, 0xf7, 0x84, 0xaa, 0x72, 0xac, 0x35, 0x4d, 0x6a, 0x2a, 0x96, 0x1a, 0xd2, 0x71, 0x5a, 0x15, 0x49, 0x74, 0x4b, 0x9f, 0xd0, 0x5e, 0x04, 0x18, 0xa4, 0xec, 0xc2, 0xe0, 0x41, 0x6e, 0x0f, 0x51, 0xcb, 0xcc, 0x24, 0x91, 0xaf, 0x50, 0xa1, 0xf4, 0x70, 0x39, 0x99, 0x7c, 0x3a, 0x85, 0x23, 0xb8, 0xb4, 0x7a, 0xfc, 0x02, 0x36, 0x5b, 0x25, 0x55, 0x97, 0x31, 0x2d, 0x5d, 0xfa, 0x98, 0xe3, 0x8a, 0x92, 0xae, 0x05, 0xdf, 0x29, 0x10, 0x67, 0x6c, 0xba, 0xc9, 0xd3, 0x00, 0xe6, 0xcf, 0xe1, 0x9e, 0xa8, 0x2c, 0x63, 0x16, 0x01, 0x3f, 0x58, 0xe2, 0x89, 0xa9, 0x0d, 0x38, 0x34, 0x1b, 0xab, 0x33, 0xff, 0xb0, 0xbb, 0x48, 0x0c, 0x5f, 0xb9, 0xb1, 0xcd, 0x2e, 0xc5, 0xf3, 0xdb, 0x47, 0xe5, 0xa5, 0x9c, 0x77, 0x0a, 0xa6, 0x20, 0x68, 0xfe, 0x7f, 0xc1, 0xad, } func expandKey(key []byte, t1 int) [64]uint16 { l := make([]byte, 128) copy(l, key) var t = len(key) var t8 = (t1 + 7) / 8 var tm = byte(255 % uint(1<<(8+uint(t1)-8*uint(t8)))) for i := len(key); i < 128; i++ { l[i] = piTable[l[i-1]+l[uint8(i-t)]] } l[128-t8] = piTable[l[128-t8]&tm] for i := 127 - t8; i >= 0; i-- { l[i] = piTable[l[i+1]^l[i+t8]] } var k [64]uint16 for i := range k { k[i] = uint16(l[2*i]) + uint16(l[2*i+1])*256 } return k } func rotl16(x uint16, b uint) uint16 { return (x >> (16 - b)) | (x << b) } func (c *rc2Cipher) Encrypt(dst, src []byte) { r0 := binary.LittleEndian.Uint16(src[0:]) r1 := binary.LittleEndian.Uint16(src[2:]) r2 := binary.LittleEndian.Uint16(src[4:]) r3 := binary.LittleEndian.Uint16(src[6:]) var j int for j <= 16 { // mix r0 r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1) r0 = rotl16(r0, 1) j++ // mix r1 r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2) r1 = rotl16(r1, 2) j++ // mix r2 r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3) r2 = rotl16(r2, 3) j++ // mix r3 r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0) r3 = rotl16(r3, 5) j++ } r0 = r0 + c.k[r3&63] r1 = r1 + c.k[r0&63] r2 = r2 + c.k[r1&63] r3 = r3 + c.k[r2&63] for j <= 40 { // mix r0 r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1) r0 = rotl16(r0, 1) j++ // mix r1 r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2) r1 = rotl16(r1, 2) j++ // mix r2 r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3) r2 = rotl16(r2, 3) j++ // mix r3 r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0) r3 = rotl16(r3, 5) j++ } r0 = r0 + c.k[r3&63] r1 = r1 + c.k[r0&63] r2 = r2 + c.k[r1&63] r3 = r3 + c.k[r2&63] for j <= 60 { // mix r0 r0 = r0 + c.k[j] + (r3 & r2) + ((^r3) & r1) r0 = rotl16(r0, 1) j++ // mix r1 r1 = r1 + c.k[j] + (r0 & r3) + ((^r0) & r2) r1 = rotl16(r1, 2) j++ // mix r2 r2 = r2 + c.k[j] + (r1 & r0) + ((^r1) & r3) r2 = rotl16(r2, 3) j++ // mix r3 r3 = r3 + c.k[j] + (r2 & r1) + ((^r2) & r0) r3 = rotl16(r3, 5) j++ } binary.LittleEndian.PutUint16(dst[0:], r0) binary.LittleEndian.PutUint16(dst[2:], r1) binary.LittleEndian.PutUint16(dst[4:], r2) binary.LittleEndian.PutUint16(dst[6:], r3) } func (c *rc2Cipher) Decrypt(dst, src []byte) { r0 := binary.LittleEndian.Uint16(src[0:]) r1 := binary.LittleEndian.Uint16(src[2:]) r2 := binary.LittleEndian.Uint16(src[4:]) r3 := binary.LittleEndian.Uint16(src[6:]) j := 63 for j >= 44 { // unmix r3 r3 = rotl16(r3, 16-5) r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0) j-- // unmix r2 r2 = rotl16(r2, 16-3) r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3) j-- // unmix r1 r1 = rotl16(r1, 16-2) r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2) j-- // unmix r0 r0 = rotl16(r0, 16-1) r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1) j-- } r3 = r3 - c.k[r2&63] r2 = r2 - c.k[r1&63] r1 = r1 - c.k[r0&63] r0 = r0 - c.k[r3&63] for j >= 20 { // unmix r3 r3 = rotl16(r3, 16-5) r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0) j-- // unmix r2 r2 = rotl16(r2, 16-3) r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3) j-- // unmix r1 r1 = rotl16(r1, 16-2) r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2) j-- // unmix r0 r0 = rotl16(r0, 16-1) r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1) j-- } r3 = r3 - c.k[r2&63] r2 = r2 - c.k[r1&63] r1 = r1 - c.k[r0&63] r0 = r0 - c.k[r3&63] for j >= 0 { // unmix r3 r3 = rotl16(r3, 16-5) r3 = r3 - c.k[j] - (r2 & r1) - ((^r2) & r0) j-- // unmix r2 r2 = rotl16(r2, 16-3) r2 = r2 - c.k[j] - (r1 & r0) - ((^r1) & r3) j-- // unmix r1 r1 = rotl16(r1, 16-2) r1 = r1 - c.k[j] - (r0 & r3) - ((^r0) & r2) j-- // unmix r0 r0 = rotl16(r0, 16-1) r0 = r0 - c.k[j] - (r3 & r2) - ((^r3) & r1) j-- } binary.LittleEndian.PutUint16(dst[0:], r0) binary.LittleEndian.PutUint16(dst[2:], r1) binary.LittleEndian.PutUint16(dst[4:], r2) binary.LittleEndian.PutUint16(dst[6:], r3) } go-pkcs12-0.2.0/internal/rc2/rc2_test.go000066400000000000000000000030761422655416100176110ustar00rootroot00000000000000// Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package rc2 import ( "bytes" "encoding/hex" "testing" ) func TestEncryptDecrypt(t *testing.T) { // TODO(dgryski): add the rest of the test vectors from the RFC var tests = []struct { key string plain string cipher string t1 int }{ { "0000000000000000", "0000000000000000", "ebb773f993278eff", 63, }, { "ffffffffffffffff", "ffffffffffffffff", "278b27e42e2f0d49", 64, }, { "3000000000000000", "1000000000000001", "30649edf9be7d2c2", 64, }, { "88", "0000000000000000", "61a8a244adacccf0", 64, }, { "88bca90e90875a", "0000000000000000", "6ccf4308974c267f", 64, }, { "88bca90e90875a7f0f79c384627bafb2", "0000000000000000", "1a807d272bbe5db1", 64, }, { "88bca90e90875a7f0f79c384627bafb2", "0000000000000000", "2269552ab0f85ca6", 128, }, { "88bca90e90875a7f0f79c384627bafb216f80a6f85920584c42fceb0be255daf1e", "0000000000000000", "5b78d3a43dfff1f1", 129, }, } for _, tt := range tests { k, _ := hex.DecodeString(tt.key) p, _ := hex.DecodeString(tt.plain) c, _ := hex.DecodeString(tt.cipher) b, _ := New(k, tt.t1) var dst [8]byte b.Encrypt(dst[:], p) if !bytes.Equal(dst[:], c) { t.Errorf("encrypt failed: got % 2x wanted % 2x\n", dst, c) } b.Decrypt(dst[:], c) if !bytes.Equal(dst[:], p) { t.Errorf("decrypt failed: got % 2x wanted % 2x\n", dst, p) } } } go-pkcs12-0.2.0/mac.go000066400000000000000000000034641422655416100143230ustar00rootroot00000000000000// Copyright 2015, 2018, 2019 Opsmate, Inc. All rights reserved. // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package pkcs12 import ( "crypto/hmac" "crypto/sha1" "crypto/sha256" "crypto/x509/pkix" "encoding/asn1" "hash" ) type macData struct { Mac digestInfo MacSalt []byte Iterations int `asn1:"optional,default:1"` } // from PKCS#7: type digestInfo struct { Algorithm pkix.AlgorithmIdentifier Digest []byte } var ( oidSHA1 = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26}) oidSHA256 = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 101, 3, 4, 2, 1}) ) func verifyMac(macData *macData, message, password []byte) error { var hFn func() hash.Hash var key []byte switch { case macData.Mac.Algorithm.Algorithm.Equal(oidSHA1): hFn = sha1.New key = pbkdf(sha1Sum, 20, 64, macData.MacSalt, password, macData.Iterations, 3, 20) case macData.Mac.Algorithm.Algorithm.Equal(oidSHA256): hFn = sha256.New key = pbkdf(sha256Sum, 32, 64, macData.MacSalt, password, macData.Iterations, 3, 32) default: return NotImplementedError("unknown digest algorithm: " + macData.Mac.Algorithm.Algorithm.String()) } mac := hmac.New(hFn, key) mac.Write(message) expectedMAC := mac.Sum(nil) if !hmac.Equal(macData.Mac.Digest, expectedMAC) { return ErrIncorrectPassword } return nil } func computeMac(macData *macData, message, password []byte) error { if !macData.Mac.Algorithm.Algorithm.Equal(oidSHA1) { return NotImplementedError("unknown digest algorithm: " + macData.Mac.Algorithm.Algorithm.String()) } key := pbkdf(sha1Sum, 20, 64, macData.MacSalt, password, macData.Iterations, 3, 20) mac := hmac.New(sha1.New, key) mac.Write(message) macData.Mac.Digest = mac.Sum(nil) return nil } go-pkcs12-0.2.0/mac_test.go000066400000000000000000000040621422655416100153550ustar00rootroot00000000000000// Copyright 2015, 2018, 2019 Opsmate, Inc. All rights reserved. // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package pkcs12 import ( "bytes" "encoding/asn1" "testing" ) func TestVerifyMac(t *testing.T) { td := macData{ Mac: digestInfo{ Digest: []byte{0x18, 0x20, 0x3d, 0xff, 0x1e, 0x16, 0xf4, 0x92, 0xf2, 0xaf, 0xc8, 0x91, 0xa9, 0xba, 0xd6, 0xca, 0x9d, 0xee, 0x51, 0x93}, }, MacSalt: []byte{1, 2, 3, 4, 5, 6, 7, 8}, Iterations: 2048, } message := []byte{11, 12, 13, 14, 15} password, _ := bmpStringZeroTerminated("") td.Mac.Algorithm.Algorithm = asn1.ObjectIdentifier([]int{1, 2, 3}) err := verifyMac(&td, message, password) if _, ok := err.(NotImplementedError); !ok { t.Errorf("err: %v", err) } td.Mac.Algorithm.Algorithm = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26}) err = verifyMac(&td, message, password) if err != ErrIncorrectPassword { t.Errorf("Expected incorrect password, got err: %v", err) } password, _ = bmpStringZeroTerminated("Sesame open") err = verifyMac(&td, message, password) if err != nil { t.Errorf("err: %v", err) } } func TestComputeMac(t *testing.T) { td := macData{ MacSalt: []byte{1, 2, 3, 4, 5, 6, 7, 8}, Iterations: 2048, } message := []byte{11, 12, 13, 14, 15} password, _ := bmpStringZeroTerminated("Sesame open") td.Mac.Algorithm.Algorithm = asn1.ObjectIdentifier([]int{1, 2, 3}) err := computeMac(&td, message, password) if _, ok := err.(NotImplementedError); !ok { t.Errorf("err: %v", err) } td.Mac.Algorithm.Algorithm = asn1.ObjectIdentifier([]int{1, 3, 14, 3, 2, 26}) err = computeMac(&td, message, password) if err != nil { t.Errorf("err: %v", err) } expectedDigest := []byte{0x18, 0x20, 0x3d, 0xff, 0x1e, 0x16, 0xf4, 0x92, 0xf2, 0xaf, 0xc8, 0x91, 0xa9, 0xba, 0xd6, 0xca, 0x9d, 0xee, 0x51, 0x93} if bytes.Compare(td.Mac.Digest, expectedDigest) != 0 { t.Errorf("Computed incorrect MAC; expected MAC to be '%d' but got '%d'", expectedDigest, td.Mac.Digest) } } go-pkcs12-0.2.0/pbkdf.go000066400000000000000000000132521422655416100146450ustar00rootroot00000000000000// Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package pkcs12 import ( "bytes" "crypto/sha1" "crypto/sha256" "math/big" ) var ( one = big.NewInt(1) ) // sha1Sum returns the SHA-1 hash of in. func sha1Sum(in []byte) []byte { sum := sha1.Sum(in) return sum[:] } // sha256Sum returns the SHA-256 hash of in. func sha256Sum(in []byte) []byte { sum := sha256.Sum256(in) return sum[:] } // fillWithRepeats returns v*ceiling(len(pattern) / v) bytes consisting of // repeats of pattern. func fillWithRepeats(pattern []byte, v int) []byte { if len(pattern) == 0 { return nil } outputLen := v * ((len(pattern) + v - 1) / v) return bytes.Repeat(pattern, (outputLen+len(pattern)-1)/len(pattern))[:outputLen] } func pbkdf(hash func([]byte) []byte, u, v int, salt, password []byte, r int, ID byte, size int) (key []byte) { // implementation of https://tools.ietf.org/html/rfc7292#appendix-B.2 , RFC text verbatim in comments // Let H be a hash function built around a compression function f: // Z_2^u x Z_2^v -> Z_2^u // (that is, H has a chaining variable and output of length u bits, and // the message input to the compression function of H is v bits). The // values for u and v are as follows: // HASH FUNCTION VALUE u VALUE v // MD2, MD5 128 512 // SHA-1 160 512 // SHA-224 224 512 // SHA-256 256 512 // SHA-384 384 1024 // SHA-512 512 1024 // SHA-512/224 224 1024 // SHA-512/256 256 1024 // Furthermore, let r be the iteration count. // We assume here that u and v are both multiples of 8, as are the // lengths of the password and salt strings (which we denote by p and s, // respectively) and the number n of pseudorandom bits required. In // addition, u and v are of course non-zero. // For information on security considerations for MD5 [19], see [25] and // [1], and on those for MD2, see [18]. // The following procedure can be used to produce pseudorandom bits for // a particular "purpose" that is identified by a byte called "ID". // This standard specifies 3 different values for the ID byte: // 1. If ID=1, then the pseudorandom bits being produced are to be used // as key material for performing encryption or decryption. // 2. If ID=2, then the pseudorandom bits being produced are to be used // as an IV (Initial Value) for encryption or decryption. // 3. If ID=3, then the pseudorandom bits being produced are to be used // as an integrity key for MACing. // 1. Construct a string, D (the "diversifier"), by concatenating v/8 // copies of ID. var D []byte for i := 0; i < v; i++ { D = append(D, ID) } // 2. Concatenate copies of the salt together to create a string S of // length v(ceiling(s/v)) bits (the final copy of the salt may be // truncated to create S). Note that if the salt is the empty // string, then so is S. S := fillWithRepeats(salt, v) // 3. Concatenate copies of the password together to create a string P // of length v(ceiling(p/v)) bits (the final copy of the password // may be truncated to create P). Note that if the password is the // empty string, then so is P. P := fillWithRepeats(password, v) // 4. Set I=S||P to be the concatenation of S and P. I := append(S, P...) // 5. Set c=ceiling(n/u). c := (size + u - 1) / u // 6. For i=1, 2, ..., c, do the following: A := make([]byte, c*u) var IjBuf []byte for i := 0; i < c; i++ { // A. Set A2=H^r(D||I). (i.e., the r-th hash of D||1, // H(H(H(... H(D||I)))) Ai := hash(append(D, I...)) for j := 1; j < r; j++ { Ai = hash(Ai) } copy(A[i*u:], Ai[:]) if i < c-1 { // skip on last iteration // B. Concatenate copies of Ai to create a string B of length v // bits (the final copy of Ai may be truncated to create B). var B []byte for len(B) < v { B = append(B, Ai[:]...) } B = B[:v] // C. Treating I as a concatenation I_0, I_1, ..., I_(k-1) of v-bit // blocks, where k=ceiling(s/v)+ceiling(p/v), modify I by // setting I_j=(I_j+B+1) mod 2^v for each j. { Bbi := new(big.Int).SetBytes(B) Ij := new(big.Int) for j := 0; j < len(I)/v; j++ { Ij.SetBytes(I[j*v : (j+1)*v]) Ij.Add(Ij, Bbi) Ij.Add(Ij, one) Ijb := Ij.Bytes() // We expect Ijb to be exactly v bytes, // if it is longer or shorter we must // adjust it accordingly. if len(Ijb) > v { Ijb = Ijb[len(Ijb)-v:] } if len(Ijb) < v { if IjBuf == nil { IjBuf = make([]byte, v) } bytesShort := v - len(Ijb) for i := 0; i < bytesShort; i++ { IjBuf[i] = 0 } copy(IjBuf[bytesShort:], Ijb) Ijb = IjBuf } copy(I[j*v:(j+1)*v], Ijb) } } } } // 7. Concatenate A_1, A_2, ..., A_c together to form a pseudorandom // bit string, A. // 8. Use the first n bits of A as the output of this entire process. return A[:size] // If the above process is being used to generate a DES key, the process // should be used to create 64 random bits, and the key's parity bits // should be set after the 64 bits have been produced. Similar concerns // hold for 2-key and 3-key triple-DES keys, for CDMF keys, and for any // similar keys with parity bits "built into them". } go-pkcs12-0.2.0/pbkdf_test.go000066400000000000000000000025131422655416100157020ustar00rootroot00000000000000// Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package pkcs12 import ( "bytes" "testing" ) func TestThatPBKDFWorksCorrectlyForLongKeys(t *testing.T) { cipherInfo := shaWithTripleDESCBC{} salt := []byte("\xff\xff\xff\xff\xff\xff\xff\xff") password, _ := bmpStringZeroTerminated("sesame") key := cipherInfo.deriveKey(salt, password, 2048) if expected := []byte("\x7c\xd9\xfd\x3e\x2b\x3b\xe7\x69\x1a\x44\xe3\xbe\xf0\xf9\xea\x0f\xb9\xb8\x97\xd4\xe3\x25\xd9\xd1"); bytes.Compare(key, expected) != 0 { t.Fatalf("expected key '%x', but found '%x'", expected, key) } } func TestThatPBKDFHandlesLeadingZeros(t *testing.T) { // This test triggers a case where I_j (in step 6C) ends up with leading zero // byte, meaning that len(Ijb) < v (leading zeros get stripped by big.Int). // This was previously causing bug whereby certain inputs would break the // derivation and produce the wrong output. key := pbkdf(sha1Sum, 20, 64, []byte("\xf3\x7e\x05\xb5\x18\x32\x4b\x4b"), []byte("\x00\x00"), 2048, 1, 24) expected := []byte("\x00\xf7\x59\xff\x47\xd1\x4d\xd0\x36\x65\xd5\x94\x3c\xb3\xc4\xa3\x9a\x25\x55\xc0\x2a\xed\x66\xe1") if bytes.Compare(key, expected) != 0 { t.Fatalf("expected key '%x', but found '%x'", expected, key) } } go-pkcs12-0.2.0/pkcs12.go000066400000000000000000000564241422655416100146720ustar00rootroot00000000000000// Copyright 2015, 2018, 2019 Opsmate, Inc. All rights reserved. // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package pkcs12 implements some of PKCS#12 (also known as P12 or PFX). // It is intended for decoding DER-encoded P12/PFX files for use with the crypto/tls // package, and for encoding P12/PFX files for use by legacy applications which // do not support newer formats. Since PKCS#12 uses weak encryption // primitives, it SHOULD NOT be used for new applications. // // Note that only DER-encoded PKCS#12 files are supported, even though PKCS#12 // allows BER encoding. This is because encoding/asn1 only supports DER. // // This package is forked from golang.org/x/crypto/pkcs12, which is frozen. // The implementation is distilled from https://tools.ietf.org/html/rfc7292 // and referenced documents. package pkcs12 // import "software.sslmate.com/src/go-pkcs12" import ( "crypto/ecdsa" "crypto/rsa" "crypto/sha1" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" "encoding/hex" "encoding/pem" "errors" "io" ) // DefaultPassword is the string "changeit", a commonly-used password for // PKCS#12 files. Due to the weak encryption used by PKCS#12, it is // RECOMMENDED that you use DefaultPassword when encoding PKCS#12 files, // and protect the PKCS#12 files using other means. const DefaultPassword = "changeit" var ( oidDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 1}) oidEncryptedDataContentType = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 7, 6}) oidFriendlyName = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 20}) oidLocalKeyID = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 21}) oidMicrosoftCSPName = asn1.ObjectIdentifier([]int{1, 3, 6, 1, 4, 1, 311, 17, 1}) oidJavaTrustStore = asn1.ObjectIdentifier([]int{2, 16, 840, 1, 113894, 746875, 1, 1}) oidAnyExtendedKeyUsage = asn1.ObjectIdentifier([]int{2, 5, 29, 37, 0}) ) type pfxPdu struct { Version int AuthSafe contentInfo MacData macData `asn1:"optional"` } type contentInfo struct { ContentType asn1.ObjectIdentifier Content asn1.RawValue `asn1:"tag:0,explicit,optional"` } type encryptedData struct { Version int EncryptedContentInfo encryptedContentInfo } type encryptedContentInfo struct { ContentType asn1.ObjectIdentifier ContentEncryptionAlgorithm pkix.AlgorithmIdentifier EncryptedContent []byte `asn1:"tag:0,optional"` } func (i encryptedContentInfo) Algorithm() pkix.AlgorithmIdentifier { return i.ContentEncryptionAlgorithm } func (i encryptedContentInfo) Data() []byte { return i.EncryptedContent } func (i *encryptedContentInfo) SetData(data []byte) { i.EncryptedContent = data } type safeBag struct { Id asn1.ObjectIdentifier Value asn1.RawValue `asn1:"tag:0,explicit"` Attributes []pkcs12Attribute `asn1:"set,optional"` } func (bag *safeBag) hasAttribute(id asn1.ObjectIdentifier) bool { for _, attr := range bag.Attributes { if attr.Id.Equal(id) { return true } } return false } type pkcs12Attribute struct { Id asn1.ObjectIdentifier Value asn1.RawValue `asn1:"set"` } type encryptedPrivateKeyInfo struct { AlgorithmIdentifier pkix.AlgorithmIdentifier EncryptedData []byte } func (i encryptedPrivateKeyInfo) Algorithm() pkix.AlgorithmIdentifier { return i.AlgorithmIdentifier } func (i encryptedPrivateKeyInfo) Data() []byte { return i.EncryptedData } func (i *encryptedPrivateKeyInfo) SetData(data []byte) { i.EncryptedData = data } // PEM block types const ( certificateType = "CERTIFICATE" privateKeyType = "PRIVATE KEY" ) // unmarshal calls asn1.Unmarshal, but also returns an error if there is any // trailing data after unmarshaling. func unmarshal(in []byte, out interface{}) error { trailing, err := asn1.Unmarshal(in, out) if err != nil { return err } if len(trailing) != 0 { return errors.New("pkcs12: trailing data found") } return nil } // ToPEM converts all "safe bags" contained in pfxData to PEM blocks. // // Deprecated: ToPEM creates invalid PEM blocks (private keys // are encoded as raw RSA or EC private keys rather than PKCS#8 despite being // labeled "PRIVATE KEY"). To decode a PKCS#12 file, use DecodeChain instead, // and use the encoding/pem package to convert to PEM if necessary. func ToPEM(pfxData []byte, password string) ([]*pem.Block, error) { encodedPassword, err := bmpStringZeroTerminated(password) if err != nil { return nil, ErrIncorrectPassword } bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword, 2) if err != nil { return nil, err } blocks := make([]*pem.Block, 0, len(bags)) for _, bag := range bags { block, err := convertBag(&bag, encodedPassword) if err != nil { return nil, err } blocks = append(blocks, block) } return blocks, nil } func convertBag(bag *safeBag, password []byte) (*pem.Block, error) { block := &pem.Block{ Headers: make(map[string]string), } for _, attribute := range bag.Attributes { k, v, err := convertAttribute(&attribute) if err != nil { return nil, err } block.Headers[k] = v } switch { case bag.Id.Equal(oidCertBag): block.Type = certificateType certsData, err := decodeCertBag(bag.Value.Bytes) if err != nil { return nil, err } block.Bytes = certsData case bag.Id.Equal(oidPKCS8ShroundedKeyBag): block.Type = privateKeyType key, err := decodePkcs8ShroudedKeyBag(bag.Value.Bytes, password) if err != nil { return nil, err } switch key := key.(type) { case *rsa.PrivateKey: block.Bytes = x509.MarshalPKCS1PrivateKey(key) case *ecdsa.PrivateKey: block.Bytes, err = x509.MarshalECPrivateKey(key) if err != nil { return nil, err } default: return nil, errors.New("found unknown private key type in PKCS#8 wrapping") } default: return nil, errors.New("don't know how to convert a safe bag of type " + bag.Id.String()) } return block, nil } func convertAttribute(attribute *pkcs12Attribute) (key, value string, err error) { isString := false switch { case attribute.Id.Equal(oidFriendlyName): key = "friendlyName" isString = true case attribute.Id.Equal(oidLocalKeyID): key = "localKeyId" case attribute.Id.Equal(oidMicrosoftCSPName): // This key is chosen to match OpenSSL. key = "Microsoft CSP Name" isString = true default: return "", "", errors.New("pkcs12: unknown attribute with OID " + attribute.Id.String()) } if isString { if err := unmarshal(attribute.Value.Bytes, &attribute.Value); err != nil { return "", "", err } if value, err = decodeBMPString(attribute.Value.Bytes); err != nil { return "", "", err } } else { var id []byte if err := unmarshal(attribute.Value.Bytes, &id); err != nil { return "", "", err } value = hex.EncodeToString(id) } return key, value, nil } // Decode extracts a certificate and private key from pfxData, which must be a DER-encoded PKCS#12 file. This function // assumes that there is only one certificate and only one private key in the // pfxData. Since PKCS#12 files often contain more than one certificate, you // probably want to use DecodeChain instead. func Decode(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, err error) { var caCerts []*x509.Certificate privateKey, certificate, caCerts, err = DecodeChain(pfxData, password) if len(caCerts) != 0 { err = errors.New("pkcs12: expected exactly two safe bags in the PFX PDU") } return } // DecodeChain extracts a certificate, a CA certificate chain, and private key // from pfxData, which must be a DER-encoded PKCS#12 file. This function assumes that there is at least one certificate // and only one private key in the pfxData. The first certificate is assumed to // be the leaf certificate, and subsequent certificates, if any, are assumed to // comprise the CA certificate chain. func DecodeChain(pfxData []byte, password string) (privateKey interface{}, certificate *x509.Certificate, caCerts []*x509.Certificate, err error) { encodedPassword, err := bmpStringZeroTerminated(password) if err != nil { return nil, nil, nil, err } bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword, 2) if err != nil { return nil, nil, nil, err } for _, bag := range bags { switch { case bag.Id.Equal(oidCertBag): certsData, err := decodeCertBag(bag.Value.Bytes) if err != nil { return nil, nil, nil, err } certs, err := x509.ParseCertificates(certsData) if err != nil { return nil, nil, nil, err } if len(certs) != 1 { err = errors.New("pkcs12: expected exactly one certificate in the certBag") return nil, nil, nil, err } if certificate == nil { certificate = certs[0] } else { caCerts = append(caCerts, certs[0]) } case bag.Id.Equal(oidPKCS8ShroundedKeyBag): if privateKey != nil { err = errors.New("pkcs12: expected exactly one key bag") return nil, nil, nil, err } if privateKey, err = decodePkcs8ShroudedKeyBag(bag.Value.Bytes, encodedPassword); err != nil { return nil, nil, nil, err } } } if certificate == nil { return nil, nil, nil, errors.New("pkcs12: certificate missing") } if privateKey == nil { return nil, nil, nil, errors.New("pkcs12: private key missing") } return } // DecodeTrustStore extracts the certificates from pfxData, which must be a DER-encoded // PKCS#12 file containing exclusively certificates with attribute 2.16.840.1.113894.746875.1.1, // which is used by Java to designate a trust anchor. func DecodeTrustStore(pfxData []byte, password string) (certs []*x509.Certificate, err error) { encodedPassword, err := bmpStringZeroTerminated(password) if err != nil { return nil, err } bags, encodedPassword, err := getSafeContents(pfxData, encodedPassword, 1) if err != nil { return nil, err } for _, bag := range bags { switch { case bag.Id.Equal(oidCertBag): if !bag.hasAttribute(oidJavaTrustStore) { return nil, errors.New("pkcs12: trust store contains a certificate that is not marked as trusted") } certsData, err := decodeCertBag(bag.Value.Bytes) if err != nil { return nil, err } parsedCerts, err := x509.ParseCertificates(certsData) if err != nil { return nil, err } if len(parsedCerts) != 1 { err = errors.New("pkcs12: expected exactly one certificate in the certBag") return nil, err } certs = append(certs, parsedCerts[0]) default: return nil, errors.New("pkcs12: expected only certificate bags") } } return } func getSafeContents(p12Data, password []byte, expectedItems int) (bags []safeBag, updatedPassword []byte, err error) { pfx := new(pfxPdu) if err := unmarshal(p12Data, pfx); err != nil { return nil, nil, errors.New("pkcs12: error reading P12 data: " + err.Error()) } if pfx.Version != 3 { return nil, nil, NotImplementedError("can only decode v3 PFX PDU's") } if !pfx.AuthSafe.ContentType.Equal(oidDataContentType) { return nil, nil, NotImplementedError("only password-protected PFX is implemented") } // unmarshal the explicit bytes in the content for type 'data' if err := unmarshal(pfx.AuthSafe.Content.Bytes, &pfx.AuthSafe.Content); err != nil { return nil, nil, err } if len(pfx.MacData.Mac.Algorithm.Algorithm) == 0 { if !(len(password) == 2 && password[0] == 0 && password[1] == 0) { return nil, nil, errors.New("pkcs12: no MAC in data") } } else if err := verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password); err != nil { if err == ErrIncorrectPassword && len(password) == 2 && password[0] == 0 && password[1] == 0 { // some implementations use an empty byte array // for the empty string password try one more // time with empty-empty password password = nil err = verifyMac(&pfx.MacData, pfx.AuthSafe.Content.Bytes, password) } if err != nil { return nil, nil, err } } var authenticatedSafe []contentInfo if err := unmarshal(pfx.AuthSafe.Content.Bytes, &authenticatedSafe); err != nil { return nil, nil, err } if len(authenticatedSafe) != expectedItems { return nil, nil, NotImplementedError("expected exactly two items in the authenticated safe") } for _, ci := range authenticatedSafe { var data []byte switch { case ci.ContentType.Equal(oidDataContentType): if err := unmarshal(ci.Content.Bytes, &data); err != nil { return nil, nil, err } case ci.ContentType.Equal(oidEncryptedDataContentType): var encryptedData encryptedData if err := unmarshal(ci.Content.Bytes, &encryptedData); err != nil { return nil, nil, err } if encryptedData.Version != 0 { return nil, nil, NotImplementedError("only version 0 of EncryptedData is supported") } if data, err = pbDecrypt(encryptedData.EncryptedContentInfo, password); err != nil { return nil, nil, err } default: return nil, nil, NotImplementedError("only data and encryptedData content types are supported in authenticated safe") } var safeContents []safeBag if err := unmarshal(data, &safeContents); err != nil { return nil, nil, err } bags = append(bags, safeContents...) } return bags, password, nil } // Encode produces pfxData containing one private key (privateKey), an // end-entity certificate (certificate), and any number of CA certificates // (caCerts). // // The private key is encrypted with the provided password, but due to the // weak encryption primitives used by PKCS#12, it is RECOMMENDED that you // specify a hard-coded password (such as pkcs12.DefaultPassword) and protect // the resulting pfxData using other means. // // The rand argument is used to provide entropy for the encryption, and // can be set to rand.Reader from the crypto/rand package. // // Encode emulates the behavior of OpenSSL's PKCS12_create: it creates two // SafeContents: one that's encrypted with RC2 and contains the certificates, // and another that is unencrypted and contains the private key shrouded with // 3DES The private key bag and the end-entity certificate bag have the // LocalKeyId attribute set to the SHA-1 fingerprint of the end-entity // certificate. func Encode(rand io.Reader, privateKey interface{}, certificate *x509.Certificate, caCerts []*x509.Certificate, password string) (pfxData []byte, err error) { encodedPassword, err := bmpStringZeroTerminated(password) if err != nil { return nil, err } var pfx pfxPdu pfx.Version = 3 var certFingerprint = sha1.Sum(certificate.Raw) var localKeyIdAttr pkcs12Attribute localKeyIdAttr.Id = oidLocalKeyID localKeyIdAttr.Value.Class = 0 localKeyIdAttr.Value.Tag = 17 localKeyIdAttr.Value.IsCompound = true if localKeyIdAttr.Value.Bytes, err = asn1.Marshal(certFingerprint[:]); err != nil { return nil, err } var certBags []safeBag var certBag *safeBag if certBag, err = makeCertBag(certificate.Raw, []pkcs12Attribute{localKeyIdAttr}); err != nil { return nil, err } certBags = append(certBags, *certBag) for _, cert := range caCerts { if certBag, err = makeCertBag(cert.Raw, []pkcs12Attribute{}); err != nil { return nil, err } certBags = append(certBags, *certBag) } var keyBag safeBag keyBag.Id = oidPKCS8ShroundedKeyBag keyBag.Value.Class = 2 keyBag.Value.Tag = 0 keyBag.Value.IsCompound = true if keyBag.Value.Bytes, err = encodePkcs8ShroudedKeyBag(rand, privateKey, encodedPassword); err != nil { return nil, err } keyBag.Attributes = append(keyBag.Attributes, localKeyIdAttr) // Construct an authenticated safe with two SafeContents. // The first SafeContents is encrypted and contains the cert bags. // The second SafeContents is unencrypted and contains the shrouded key bag. var authenticatedSafe [2]contentInfo if authenticatedSafe[0], err = makeSafeContents(rand, certBags, encodedPassword); err != nil { return nil, err } if authenticatedSafe[1], err = makeSafeContents(rand, []safeBag{keyBag}, nil); err != nil { return nil, err } var authenticatedSafeBytes []byte if authenticatedSafeBytes, err = asn1.Marshal(authenticatedSafe[:]); err != nil { return nil, err } // compute the MAC pfx.MacData.Mac.Algorithm.Algorithm = oidSHA1 pfx.MacData.MacSalt = make([]byte, 8) if _, err = rand.Read(pfx.MacData.MacSalt); err != nil { return nil, err } pfx.MacData.Iterations = 1 if err = computeMac(&pfx.MacData, authenticatedSafeBytes, encodedPassword); err != nil { return nil, err } pfx.AuthSafe.ContentType = oidDataContentType pfx.AuthSafe.Content.Class = 2 pfx.AuthSafe.Content.Tag = 0 pfx.AuthSafe.Content.IsCompound = true if pfx.AuthSafe.Content.Bytes, err = asn1.Marshal(authenticatedSafeBytes); err != nil { return nil, err } if pfxData, err = asn1.Marshal(pfx); err != nil { return nil, errors.New("pkcs12: error writing P12 data: " + err.Error()) } return } // EncodeTrustStore produces pfxData containing any number of CA certificates // (certs) to be trusted. The certificates will be marked with a special OID that // allow it to be used as a Java TrustStore in Java 1.8 and newer. // // Due to the weak encryption primitives used by PKCS#12, it is RECOMMENDED that // you specify a hard-coded password (such as pkcs12.DefaultPassword) and protect // the resulting pfxData using other means. // // The rand argument is used to provide entropy for the encryption, and // can be set to rand.Reader from the crypto/rand package. // // EncodeTrustStore creates a single SafeContents that's encrypted with RC2 // and contains the certificates. // // The Subject of the certificates are used as the Friendly Names (Aliases) // within the resulting pfxData. If certificates share a Subject, then the // resulting Friendly Names (Aliases) will be identical, which Java may treat as // the same entry when used as a Java TrustStore, e.g. with `keytool`. To // customize the Friendly Names, use EncodeTrustStoreEntries. func EncodeTrustStore(rand io.Reader, certs []*x509.Certificate, password string) (pfxData []byte, err error) { var certsWithFriendlyNames []TrustStoreEntry for _, cert := range certs { certsWithFriendlyNames = append(certsWithFriendlyNames, TrustStoreEntry{ Cert: cert, FriendlyName: cert.Subject.String(), }) } return EncodeTrustStoreEntries(rand, certsWithFriendlyNames, password) } // TrustStoreEntry represents an entry in a Java TrustStore. type TrustStoreEntry struct { Cert *x509.Certificate FriendlyName string } // EncodeTrustStoreEntries produces pfxData containing any number of CA // certificates (entries) to be trusted. The certificates will be marked with a // special OID that allow it to be used as a Java TrustStore in Java 1.8 and newer. // // This is identical to EncodeTrustStore, but also allows for setting specific // Friendly Names (Aliases) to be used per certificate, by specifying a slice // of TrustStoreEntry. // // If the same Friendly Name is used for more than one certificate, then the // resulting Friendly Names (Aliases) in the pfxData will be identical, which Java // may treat as the same entry when used as a Java TrustStore, e.g. with `keytool`. // // Due to the weak encryption primitives used by PKCS#12, it is RECOMMENDED that // you specify a hard-coded password (such as pkcs12.DefaultPassword) and protect // the resulting pfxData using other means. // // The rand argument is used to provide entropy for the encryption, and // can be set to rand.Reader from the crypto/rand package. // // EncodeTrustStoreEntries creates a single SafeContents that's encrypted // with RC2 and contains the certificates. func EncodeTrustStoreEntries(rand io.Reader, entries []TrustStoreEntry, password string) (pfxData []byte, err error) { encodedPassword, err := bmpStringZeroTerminated(password) if err != nil { return nil, err } var pfx pfxPdu pfx.Version = 3 var certAttributes []pkcs12Attribute extKeyUsageOidBytes, err := asn1.Marshal(oidAnyExtendedKeyUsage) if err != nil { return nil, err } // the oidJavaTrustStore attribute contains the EKUs for which // this trust anchor will be valid certAttributes = append(certAttributes, pkcs12Attribute{ Id: oidJavaTrustStore, Value: asn1.RawValue{ Class: 0, Tag: 17, IsCompound: true, Bytes: extKeyUsageOidBytes, }, }) var certBags []safeBag for _, entry := range entries { bmpFriendlyName, err := bmpString(entry.FriendlyName) if err != nil { return nil, err } encodedFriendlyName, err := asn1.Marshal(asn1.RawValue{ Class: 0, Tag: 30, IsCompound: false, Bytes: bmpFriendlyName, }) if err != nil { return nil, err } friendlyName := pkcs12Attribute{ Id: oidFriendlyName, Value: asn1.RawValue{ Class: 0, Tag: 17, IsCompound: true, Bytes: encodedFriendlyName, }, } certBag, err := makeCertBag(entry.Cert.Raw, append(certAttributes, friendlyName)) if err != nil { return nil, err } certBags = append(certBags, *certBag) } // Construct an authenticated safe with one SafeContent. // The SafeContents is encrypted and contains the cert bags. var authenticatedSafe [1]contentInfo if authenticatedSafe[0], err = makeSafeContents(rand, certBags, encodedPassword); err != nil { return nil, err } var authenticatedSafeBytes []byte if authenticatedSafeBytes, err = asn1.Marshal(authenticatedSafe[:]); err != nil { return nil, err } // compute the MAC pfx.MacData.Mac.Algorithm.Algorithm = oidSHA1 pfx.MacData.MacSalt = make([]byte, 8) if _, err = rand.Read(pfx.MacData.MacSalt); err != nil { return nil, err } pfx.MacData.Iterations = 1 if err = computeMac(&pfx.MacData, authenticatedSafeBytes, encodedPassword); err != nil { return nil, err } pfx.AuthSafe.ContentType = oidDataContentType pfx.AuthSafe.Content.Class = 2 pfx.AuthSafe.Content.Tag = 0 pfx.AuthSafe.Content.IsCompound = true if pfx.AuthSafe.Content.Bytes, err = asn1.Marshal(authenticatedSafeBytes); err != nil { return nil, err } if pfxData, err = asn1.Marshal(pfx); err != nil { return nil, errors.New("pkcs12: error writing P12 data: " + err.Error()) } return } func makeCertBag(certBytes []byte, attributes []pkcs12Attribute) (certBag *safeBag, err error) { certBag = new(safeBag) certBag.Id = oidCertBag certBag.Value.Class = 2 certBag.Value.Tag = 0 certBag.Value.IsCompound = true if certBag.Value.Bytes, err = encodeCertBag(certBytes); err != nil { return nil, err } certBag.Attributes = attributes return } func makeSafeContents(rand io.Reader, bags []safeBag, password []byte) (ci contentInfo, err error) { var data []byte if data, err = asn1.Marshal(bags); err != nil { return } if password == nil { ci.ContentType = oidDataContentType ci.Content.Class = 2 ci.Content.Tag = 0 ci.Content.IsCompound = true if ci.Content.Bytes, err = asn1.Marshal(data); err != nil { return } } else { randomSalt := make([]byte, 8) if _, err = rand.Read(randomSalt); err != nil { return } var algo pkix.AlgorithmIdentifier algo.Algorithm = oidPBEWithSHAAnd40BitRC2CBC if algo.Parameters.FullBytes, err = asn1.Marshal(pbeParams{Salt: randomSalt, Iterations: 2048}); err != nil { return } var encryptedData encryptedData encryptedData.Version = 0 encryptedData.EncryptedContentInfo.ContentType = oidDataContentType encryptedData.EncryptedContentInfo.ContentEncryptionAlgorithm = algo if err = pbEncrypt(&encryptedData.EncryptedContentInfo, data, password); err != nil { return } ci.ContentType = oidEncryptedDataContentType ci.Content.Class = 2 ci.Content.Tag = 0 ci.Content.IsCompound = true if ci.Content.Bytes, err = asn1.Marshal(encryptedData); err != nil { return } } return } go-pkcs12-0.2.0/pkcs12_test.go000066400000000000000000000327641422655416100157320ustar00rootroot00000000000000// Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package pkcs12 import ( "crypto/rand" "crypto/rsa" "crypto/tls" "crypto/x509" "encoding/base64" "encoding/pem" "testing" ) func TestPfx(t *testing.T) { for commonName, base64P12 := range testdata { p12, _ := base64.StdEncoding.DecodeString(base64P12) priv, cert, err := Decode(p12, "") if err != nil { t.Fatal(err) } if err := priv.(*rsa.PrivateKey).Validate(); err != nil { t.Errorf("error while validating private key: %v", err) } if cert.Subject.CommonName != commonName { t.Errorf("expected common name to be %q, but found %q", commonName, cert.Subject.CommonName) } } } func TestPEM(t *testing.T) { for commonName, base64P12 := range testdata { p12, _ := base64.StdEncoding.DecodeString(base64P12) blocks, err := ToPEM(p12, "") if err != nil { t.Fatalf("error while converting to PEM: %s", err) } var pemData []byte for _, b := range blocks { pemData = append(pemData, pem.EncodeToMemory(b)...) } cert, err := tls.X509KeyPair(pemData, pemData) if err != nil { t.Errorf("err while converting to key pair: %v", err) } config := tls.Config{ Certificates: []tls.Certificate{cert}, } config.BuildNameToCertificate() if _, exists := config.NameToCertificate[commonName]; !exists { t.Errorf("did not find our cert in PEM?: %v", config.NameToCertificate) } } } func TestTrustStore(t *testing.T) { for commonName, base64P12 := range testdata { p12, _ := base64.StdEncoding.DecodeString(base64P12) _, cert, err := Decode(p12, "") if err != nil { t.Fatal(err) } pfxData, err := EncodeTrustStore(rand.Reader, []*x509.Certificate{cert}, "password") if err != nil { t.Fatal(err) } decodedCerts, err := DecodeTrustStore(pfxData, "password") if err != nil { t.Fatal(err) } if len(decodedCerts) != 1 { t.Fatal("Unexpected number of certs") } if decodedCerts[0].Subject.CommonName != commonName { t.Errorf("expected common name to be %q, but found %q", commonName, decodedCerts[0].Subject.CommonName) } } } func TestPBES2(t *testing.T) { // This P12 PDU is a self-signed certificate exported via Windows certmgr. // It is encrypted with the following options (verified via openssl): PBES2, PBKDF2, AES-256-CBC, Iteration 2000, PRF hmacWithSHA256 commonName := "*.ad.standalone.com" base64P12 := `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` p12, _ := base64.StdEncoding.DecodeString(base64P12) pk, cert, caCerts, err := DecodeChain(p12, "password") if err != nil { t.Fatal(err) } rsaPk, ok := pk.(*rsa.PrivateKey) if !ok { t.Error("could not cast to rsa private key") } if !rsaPk.PublicKey.Equal(cert.PublicKey) { t.Error("public key embedded in private key not equal to public key of certificate") } if cert.Subject.CommonName != commonName { t.Errorf("unexpected leaf cert common name, got %s, want %s", cert.Subject.CommonName, commonName) } if len(caCerts) != 0 { t.Errorf("unexpected # of caCerts: got %d, want 0", len(caCerts)) } } var testdata = map[string]string{ // 'null' password test case "Windows Azure Tools": `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`, // empty string password test case "testing@example.com": `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 HQ8CAggA`, } go-pkcs12-0.2.0/safebags.go000066400000000000000000000064711422655416100153370ustar00rootroot00000000000000// Copyright 2015, 2018, 2019 Opsmate, Inc. All rights reserved. // Copyright 2015 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package pkcs12 import ( "crypto/x509" "encoding/asn1" "errors" "io" ) var ( // see https://tools.ietf.org/html/rfc7292#appendix-D oidCertTypeX509Certificate = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 9, 22, 1}) oidPKCS8ShroundedKeyBag = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 2}) oidCertBag = asn1.ObjectIdentifier([]int{1, 2, 840, 113549, 1, 12, 10, 1, 3}) ) type certBag struct { Id asn1.ObjectIdentifier Data []byte `asn1:"tag:0,explicit"` } func decodePkcs8ShroudedKeyBag(asn1Data, password []byte) (privateKey interface{}, err error) { pkinfo := new(encryptedPrivateKeyInfo) if err = unmarshal(asn1Data, pkinfo); err != nil { return nil, errors.New("pkcs12: error decoding PKCS#8 shrouded key bag: " + err.Error()) } pkData, err := pbDecrypt(pkinfo, password) if err != nil { return nil, errors.New("pkcs12: error decrypting PKCS#8 shrouded key bag: " + err.Error()) } ret := new(asn1.RawValue) if err = unmarshal(pkData, ret); err != nil { return nil, errors.New("pkcs12: error unmarshaling decrypted private key: " + err.Error()) } if privateKey, err = x509.ParsePKCS8PrivateKey(pkData); err != nil { return nil, errors.New("pkcs12: error parsing PKCS#8 private key: " + err.Error()) } return privateKey, nil } func encodePkcs8ShroudedKeyBag(rand io.Reader, privateKey interface{}, password []byte) (asn1Data []byte, err error) { var pkData []byte if pkData, err = x509.MarshalPKCS8PrivateKey(privateKey); err != nil { return nil, errors.New("pkcs12: error encoding PKCS#8 private key: " + err.Error()) } randomSalt := make([]byte, 8) if _, err = rand.Read(randomSalt); err != nil { return nil, errors.New("pkcs12: error reading random salt: " + err.Error()) } var paramBytes []byte if paramBytes, err = asn1.Marshal(pbeParams{Salt: randomSalt, Iterations: 2048}); err != nil { return nil, errors.New("pkcs12: error encoding params: " + err.Error()) } var pkinfo encryptedPrivateKeyInfo pkinfo.AlgorithmIdentifier.Algorithm = oidPBEWithSHAAnd3KeyTripleDESCBC pkinfo.AlgorithmIdentifier.Parameters.FullBytes = paramBytes if err = pbEncrypt(&pkinfo, pkData, password); err != nil { return nil, errors.New("pkcs12: error encrypting PKCS#8 shrouded key bag: " + err.Error()) } if asn1Data, err = asn1.Marshal(pkinfo); err != nil { return nil, errors.New("pkcs12: error encoding PKCS#8 shrouded key bag: " + err.Error()) } return asn1Data, nil } func decodeCertBag(asn1Data []byte) (x509Certificates []byte, err error) { bag := new(certBag) if err := unmarshal(asn1Data, bag); err != nil { return nil, errors.New("pkcs12: error decoding cert bag: " + err.Error()) } if !bag.Id.Equal(oidCertTypeX509Certificate) { return nil, NotImplementedError("only X509 certificates are supported") } return bag.Data, nil } func encodeCertBag(x509Certificates []byte) (asn1Data []byte, err error) { var bag certBag bag.Id = oidCertTypeX509Certificate bag.Data = x509Certificates if asn1Data, err = asn1.Marshal(bag); err != nil { return nil, errors.New("pkcs12: error encoding cert bag: " + err.Error()) } return asn1Data, nil }